From ad6367e61a750a90fa562bd2d7c45e8a7383f7e8 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 07:48:18 +0100 Subject: [PATCH 01/15] switch to deno for mcp run python --- Makefile | 2 +- mcp-run-python/.prettierignore | 2 - mcp-run-python/README.md | 16 +- mcp-run-python/cli.js | 5 - mcp-run-python/deno.json | 18 + mcp-run-python/deno.lock | 1078 +++++++ mcp-run-python/eslint.config.mjs | 4 - mcp-run-python/inline_python.js | 15 - mcp-run-python/package-lock.json | 2774 ----------------- mcp-run-python/package.json | 51 - mcp-run-python/pyproject.toml | 2 +- mcp-run-python/src/index.ts | 145 - mcp-run-python/src/main.ts | 170 + mcp-run-python/src/prepareEnvCode.d.ts | 1 - .../src/{prepare_env.py => prepareEnvCode.ts} | 4 +- mcp-run-python/src/runCode.ts | 170 +- mcp-run-python/tsconfig.json | 18 - 17 files changed, 1371 insertions(+), 3104 deletions(-) delete mode 100644 mcp-run-python/.prettierignore delete mode 100755 mcp-run-python/cli.js create mode 100644 mcp-run-python/deno.json create mode 100644 mcp-run-python/deno.lock delete mode 100644 mcp-run-python/eslint.config.mjs delete mode 100644 mcp-run-python/inline_python.js delete mode 100644 mcp-run-python/package-lock.json delete mode 100644 mcp-run-python/package.json delete mode 100644 mcp-run-python/src/index.ts create mode 100644 mcp-run-python/src/main.ts delete mode 100644 mcp-run-python/src/prepareEnvCode.d.ts rename mcp-run-python/src/{prepare_env.py => prepareEnvCode.ts} (98%) delete mode 100644 mcp-run-python/tsconfig.json diff --git a/Makefile b/Makefile index 3b7e78a788..911cac7573 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ lint: ## Lint the code .PHONY: lint-js lint-js: ## Lint JS and TS code - cd mcp-run-python && npm run lint + cd mcp-run-python && deno task lint-format .PHONY: typecheck-pyright typecheck-pyright: diff --git a/mcp-run-python/.prettierignore b/mcp-run-python/.prettierignore deleted file mode 100644 index b947077876..0000000000 --- a/mcp-run-python/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -dist/ diff --git a/mcp-run-python/README.md b/mcp-run-python/README.md index a9b4a94221..1a8d4a4713 100644 --- a/mcp-run-python/README.md +++ b/mcp-run-python/README.md @@ -1,9 +1,11 @@ # MCP Run Python -[Model Context Protocol](https://modelcontextprotocol.io/) server to run Python code in a sandbox. +[Model Context Protocol](https://modelcontextprotocol.io/) server to run Python +code in a sandbox. -The code is executed using [pyodide](https://pyodide.org) in node and is therefore isolated from -the rest of the operating system. +The code is executed using [pyodide](https://pyodide.org) in +[deno](https://deno.com/) and is therefore isolated from the rest of the +operating system. The server can be run with just npx thus: @@ -13,5 +15,9 @@ npx @pydantic/mcp-run-python [stdio|sse] where: -- `stdio` runs the server with the [Stdio MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) — suitable for running the process as a subprocess locally -- and `sse` runs the server with the [SSE MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) — running the server as an HTTP server to connect locally or remotely +- `stdio` runs the server with the + [Stdio MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) + — suitable for running the process as a subprocess locally +- and `sse` runs the server with the + [SSE MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) + — running the server as an HTTP server to connect locally or remotely diff --git a/mcp-run-python/cli.js b/mcp-run-python/cli.js deleted file mode 100755 index 3653bd6c65..0000000000 --- a/mcp-run-python/cli.js +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env node - -const { main } = require('./dist/index.js') - -main() diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json new file mode 100644 index 0000000000..c6fdfd5f95 --- /dev/null +++ b/mcp-run-python/deno.json @@ -0,0 +1,18 @@ +{ + "name": "@pydantic/mcp-run-python", + "version": "0.0.5", + "license": "MIT", + "nodeModulesDir": "auto", + "exports": { + ".": "./dist/index.js" + }, + "tasks": { + "lint-format": "deno fmt && deno lint && deno check src" + }, + "imports": { + "@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.8.0", + "express": "npm:express@^4.21.2", + "pyodide": "npm:pyodide@^0.27.4", + "zod": "npm:zod@^3.24.2" + } +} diff --git a/mcp-run-python/deno.lock b/mcp-run-python/deno.lock new file mode 100644 index 0000000000..09ea5ebdb6 --- /dev/null +++ b/mcp-run-python/deno.lock @@ -0,0 +1,1078 @@ +{ + "version": "4", + "specifiers": { + "npm:@modelcontextprotocol/sdk@^1.8.0": "1.8.0_express@5.1.0_zod@3.24.2", + "npm:eslint@*": "9.23.0", + "npm:express@^4.21.2": "4.21.2", + "npm:pyodide@~0.27.4": "0.27.4", + "npm:zod@^3.24.2": "3.24.2" + }, + "npm": { + "@eslint-community/eslint-utils@4.5.1_eslint@9.23.0": { + "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", + "dependencies": [ + "eslint", + "eslint-visitor-keys@3.4.3" + ] + }, + "@eslint-community/regexpp@4.12.1": { + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==" + }, + "@eslint/config-array@0.19.2": { + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dependencies": [ + "@eslint/object-schema", + "debug@4.4.0", + "minimatch" + ] + }, + "@eslint/config-helpers@0.2.0": { + "integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==" + }, + "@eslint/core@0.12.0": { + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dependencies": [ + "@types/json-schema" + ] + }, + "@eslint/eslintrc@3.3.1": { + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dependencies": [ + "ajv", + "debug@4.4.0", + "espree", + "globals", + "ignore", + "import-fresh", + "js-yaml", + "minimatch", + "strip-json-comments" + ] + }, + "@eslint/js@9.23.0": { + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==" + }, + "@eslint/object-schema@2.1.6": { + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==" + }, + "@eslint/plugin-kit@0.2.7": { + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "dependencies": [ + "@eslint/core", + "levn" + ] + }, + "@humanfs/core@0.19.1": { + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==" + }, + "@humanfs/node@0.16.6": { + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dependencies": [ + "@humanfs/core", + "@humanwhocodes/retry@0.3.1" + ] + }, + "@humanwhocodes/module-importer@1.0.1": { + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + }, + "@humanwhocodes/retry@0.3.1": { + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==" + }, + "@humanwhocodes/retry@0.4.2": { + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==" + }, + "@modelcontextprotocol/sdk@1.8.0_express@5.1.0_zod@3.24.2": { + "integrity": "sha512-e06W7SwrontJDHwCawNO5SGxG+nU9AAx+jpHHZqGl/WrDBdWOpvirC+s58VpJTB5QemI4jTRcjWT4Pt3Q1NPQQ==", + "dependencies": [ + "content-type", + "cors", + "cross-spawn", + "eventsource", + "express@5.1.0", + "express-rate-limit", + "pkce-challenge", + "raw-body@3.0.0", + "zod", + "zod-to-json-schema" + ] + }, + "@types/estree@1.0.7": { + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==" + }, + "@types/json-schema@7.0.15": { + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "accepts@1.3.8": { + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": [ + "mime-types@2.1.35", + "negotiator@0.6.3" + ] + }, + "accepts@2.0.0": { + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dependencies": [ + "mime-types@3.0.1", + "negotiator@1.0.0" + ] + }, + "acorn-jsx@5.3.2_acorn@8.14.1": { + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dependencies": [ + "acorn" + ] + }, + "acorn@8.14.1": { + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==" + }, + "ajv@6.12.6": { + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": [ + "fast-deep-equal", + "fast-json-stable-stringify", + "json-schema-traverse", + "uri-js" + ] + }, + "ansi-styles@4.3.0": { + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": [ + "color-convert" + ] + }, + "argparse@2.0.1": { + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-flatten@1.1.1": { + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "balanced-match@1.0.2": { + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "body-parser@1.20.3": { + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": [ + "bytes", + "content-type", + "debug@2.6.9", + "depd", + "destroy", + "http-errors", + "iconv-lite@0.4.24", + "on-finished", + "qs@6.13.0", + "raw-body@2.5.2", + "type-is@1.6.18", + "unpipe" + ] + }, + "body-parser@2.2.0": { + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "dependencies": [ + "bytes", + "content-type", + "debug@4.4.0", + "http-errors", + "iconv-lite@0.6.3", + "on-finished", + "qs@6.14.0", + "raw-body@3.0.0", + "type-is@2.0.1" + ] + }, + "brace-expansion@1.1.11": { + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": [ + "balanced-match", + "concat-map" + ] + }, + "bytes@3.1.2": { + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind-apply-helpers@1.0.2": { + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": [ + "es-errors", + "function-bind" + ] + }, + "call-bound@1.0.4": { + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dependencies": [ + "call-bind-apply-helpers", + "get-intrinsic" + ] + }, + "callsites@3.1.0": { + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "chalk@4.1.2": { + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": [ + "ansi-styles", + "supports-color" + ] + }, + "color-convert@2.0.1": { + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": [ + "color-name" + ] + }, + "color-name@1.1.4": { + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "concat-map@0.0.1": { + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "content-disposition@0.5.4": { + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": [ + "safe-buffer" + ] + }, + "content-disposition@1.0.0": { + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "dependencies": [ + "safe-buffer" + ] + }, + "content-type@1.0.5": { + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "cookie-signature@1.0.6": { + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cookie-signature@1.2.2": { + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==" + }, + "cookie@0.7.1": { + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" + }, + "cors@2.8.5": { + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": [ + "object-assign", + "vary" + ] + }, + "cross-spawn@7.0.6": { + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dependencies": [ + "path-key", + "shebang-command", + "which" + ] + }, + "debug@2.6.9": { + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": [ + "ms@2.0.0" + ] + }, + "debug@4.4.0": { + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": [ + "ms@2.1.3" + ] + }, + "deep-is@0.1.4": { + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "depd@2.0.0": { + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy@1.2.0": { + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "dunder-proto@1.0.1": { + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": [ + "call-bind-apply-helpers", + "es-errors", + "gopd" + ] + }, + "ee-first@1.1.1": { + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "encodeurl@1.0.2": { + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "encodeurl@2.0.0": { + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, + "es-define-property@1.0.1": { + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors@1.3.0": { + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-object-atoms@1.1.1": { + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": [ + "es-errors" + ] + }, + "escape-html@1.0.3": { + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp@4.0.0": { + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint-scope@8.3.0": { + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dependencies": [ + "esrecurse", + "estraverse" + ] + }, + "eslint-visitor-keys@3.4.3": { + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" + }, + "eslint-visitor-keys@4.2.0": { + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==" + }, + "eslint@9.23.0": { + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", + "dependencies": [ + "@eslint-community/eslint-utils", + "@eslint-community/regexpp", + "@eslint/config-array", + "@eslint/config-helpers", + "@eslint/core", + "@eslint/eslintrc", + "@eslint/js", + "@eslint/plugin-kit", + "@humanfs/node", + "@humanwhocodes/module-importer", + "@humanwhocodes/retry@0.4.2", + "@types/estree", + "@types/json-schema", + "ajv", + "chalk", + "cross-spawn", + "debug@4.4.0", + "escape-string-regexp", + "eslint-scope", + "eslint-visitor-keys@4.2.0", + "espree", + "esquery", + "esutils", + "fast-deep-equal", + "file-entry-cache", + "find-up", + "glob-parent", + "ignore", + "imurmurhash", + "is-glob", + "json-stable-stringify-without-jsonify", + "lodash.merge", + "minimatch", + "natural-compare", + "optionator" + ] + }, + "espree@10.3.0_acorn@8.14.1": { + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dependencies": [ + "acorn", + "acorn-jsx", + "eslint-visitor-keys@4.2.0" + ] + }, + "esquery@1.6.0": { + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dependencies": [ + "estraverse" + ] + }, + "esrecurse@4.3.0": { + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": [ + "estraverse" + ] + }, + "estraverse@5.3.0": { + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "esutils@2.0.3": { + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag@1.8.1": { + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "eventsource-parser@3.0.1": { + "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==" + }, + "eventsource@3.0.6": { + "integrity": "sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==", + "dependencies": [ + "eventsource-parser" + ] + }, + "express-rate-limit@7.5.0_express@5.1.0": { + "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", + "dependencies": [ + "express@5.1.0" + ] + }, + "express@4.21.2": { + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dependencies": [ + "accepts@1.3.8", + "array-flatten", + "body-parser@1.20.3", + "content-disposition@0.5.4", + "content-type", + "cookie", + "cookie-signature@1.0.6", + "debug@2.6.9", + "depd", + "encodeurl@2.0.0", + "escape-html", + "etag", + "finalhandler@1.3.1", + "fresh@0.5.2", + "http-errors", + "merge-descriptors@1.0.3", + "methods", + "on-finished", + "parseurl", + "path-to-regexp@0.1.12", + "proxy-addr", + "qs@6.13.0", + "range-parser", + "safe-buffer", + "send@0.19.0", + "serve-static@1.16.2", + "setprototypeof", + "statuses", + "type-is@1.6.18", + "utils-merge", + "vary" + ] + }, + "express@5.1.0": { + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "dependencies": [ + "accepts@2.0.0", + "body-parser@2.2.0", + "content-disposition@1.0.0", + "content-type", + "cookie", + "cookie-signature@1.2.2", + "debug@4.4.0", + "encodeurl@2.0.0", + "escape-html", + "etag", + "finalhandler@2.1.0", + "fresh@2.0.0", + "http-errors", + "merge-descriptors@2.0.0", + "mime-types@3.0.1", + "on-finished", + "once", + "parseurl", + "proxy-addr", + "qs@6.14.0", + "range-parser", + "router", + "send@1.2.0", + "serve-static@2.2.0", + "statuses", + "type-is@2.0.1", + "vary" + ] + }, + "fast-deep-equal@3.1.3": { + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify@2.1.0": { + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein@2.0.6": { + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "file-entry-cache@8.0.0": { + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dependencies": [ + "flat-cache" + ] + }, + "finalhandler@1.3.1": { + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": [ + "debug@2.6.9", + "encodeurl@2.0.0", + "escape-html", + "on-finished", + "parseurl", + "statuses", + "unpipe" + ] + }, + "finalhandler@2.1.0": { + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "dependencies": [ + "debug@4.4.0", + "encodeurl@2.0.0", + "escape-html", + "on-finished", + "parseurl", + "statuses" + ] + }, + "find-up@5.0.0": { + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": [ + "locate-path", + "path-exists" + ] + }, + "flat-cache@4.0.1": { + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dependencies": [ + "flatted", + "keyv" + ] + }, + "flatted@3.3.3": { + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==" + }, + "forwarded@0.2.0": { + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh@0.5.2": { + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fresh@2.0.0": { + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==" + }, + "function-bind@1.1.2": { + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic@1.3.0": { + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": [ + "call-bind-apply-helpers", + "es-define-property", + "es-errors", + "es-object-atoms", + "function-bind", + "get-proto", + "gopd", + "has-symbols", + "hasown", + "math-intrinsics" + ] + }, + "get-proto@1.0.1": { + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": [ + "dunder-proto", + "es-object-atoms" + ] + }, + "glob-parent@6.0.2": { + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": [ + "is-glob" + ] + }, + "globals@14.0.0": { + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==" + }, + "gopd@1.2.0": { + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, + "has-flag@4.0.0": { + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols@1.1.0": { + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "hasown@2.0.2": { + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": [ + "function-bind" + ] + }, + "http-errors@2.0.0": { + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": [ + "depd", + "inherits", + "setprototypeof", + "statuses", + "toidentifier" + ] + }, + "iconv-lite@0.4.24": { + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": [ + "safer-buffer" + ] + }, + "iconv-lite@0.6.3": { + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": [ + "safer-buffer" + ] + }, + "ignore@5.3.2": { + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==" + }, + "import-fresh@3.3.1": { + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dependencies": [ + "parent-module", + "resolve-from" + ] + }, + "imurmurhash@0.1.4": { + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "inherits@2.0.4": { + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js@1.9.1": { + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-extglob@2.1.1": { + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob@4.0.3": { + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": [ + "is-extglob" + ] + }, + "is-promise@4.0.0": { + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" + }, + "isexe@2.0.0": { + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "js-yaml@4.1.0": { + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": [ + "argparse" + ] + }, + "json-buffer@3.0.1": { + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "json-schema-traverse@0.4.1": { + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify@1.0.1": { + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "keyv@4.5.4": { + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": [ + "json-buffer" + ] + }, + "levn@0.4.1": { + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": [ + "prelude-ls", + "type-check" + ] + }, + "locate-path@6.0.0": { + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": [ + "p-locate" + ] + }, + "lodash.merge@4.6.2": { + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "math-intrinsics@1.1.0": { + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "media-typer@0.3.0": { + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "media-typer@1.1.0": { + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" + }, + "merge-descriptors@1.0.3": { + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + }, + "merge-descriptors@2.0.0": { + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==" + }, + "methods@1.1.2": { + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "mime-db@1.52.0": { + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-db@1.54.0": { + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==" + }, + "mime-types@2.1.35": { + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": [ + "mime-db@1.52.0" + ] + }, + "mime-types@3.0.1": { + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dependencies": [ + "mime-db@1.54.0" + ] + }, + "mime@1.6.0": { + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "minimatch@3.1.2": { + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": [ + "brace-expansion" + ] + }, + "ms@2.0.0": { + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "ms@2.1.3": { + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "natural-compare@1.4.0": { + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "negotiator@0.6.3": { + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "negotiator@1.0.0": { + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==" + }, + "object-assign@4.1.1": { + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect@1.13.4": { + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" + }, + "on-finished@2.4.1": { + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": [ + "ee-first" + ] + }, + "once@1.4.0": { + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": [ + "wrappy" + ] + }, + "optionator@0.9.4": { + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dependencies": [ + "deep-is", + "fast-levenshtein", + "levn", + "prelude-ls", + "type-check", + "word-wrap" + ] + }, + "p-limit@3.1.0": { + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": [ + "yocto-queue" + ] + }, + "p-locate@5.0.0": { + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": [ + "p-limit" + ] + }, + "parent-module@1.0.1": { + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": [ + "callsites" + ] + }, + "parseurl@1.3.3": { + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists@4.0.0": { + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-key@3.1.1": { + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-to-regexp@0.1.12": { + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + }, + "path-to-regexp@8.2.0": { + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==" + }, + "pkce-challenge@4.1.0": { + "integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==" + }, + "prelude-ls@1.2.1": { + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "proxy-addr@2.0.7": { + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": [ + "forwarded", + "ipaddr.js" + ] + }, + "punycode@2.3.1": { + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" + }, + "pyodide@0.27.4": { + "integrity": "sha512-2y3ySHCBmyzYDUlB939SaU3n7RxYQxwnGHgdakW/CPrNFX2L9fC+4nfJWQJH8a0ruQa8bBZSKCImMt/cq15RiQ==", + "dependencies": [ + "ws" + ] + }, + "qs@6.13.0": { + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": [ + "side-channel" + ] + }, + "qs@6.14.0": { + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dependencies": [ + "side-channel" + ] + }, + "range-parser@1.2.1": { + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body@2.5.2": { + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": [ + "bytes", + "http-errors", + "iconv-lite@0.4.24", + "unpipe" + ] + }, + "raw-body@3.0.0": { + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "dependencies": [ + "bytes", + "http-errors", + "iconv-lite@0.6.3", + "unpipe" + ] + }, + "resolve-from@4.0.0": { + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "router@2.2.0": { + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dependencies": [ + "debug@4.4.0", + "depd", + "is-promise", + "parseurl", + "path-to-regexp@8.2.0" + ] + }, + "safe-buffer@5.2.1": { + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer@2.1.2": { + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send@0.19.0": { + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": [ + "debug@2.6.9", + "depd", + "destroy", + "encodeurl@1.0.2", + "escape-html", + "etag", + "fresh@0.5.2", + "http-errors", + "mime", + "ms@2.1.3", + "on-finished", + "range-parser", + "statuses" + ] + }, + "send@1.2.0": { + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "dependencies": [ + "debug@4.4.0", + "encodeurl@2.0.0", + "escape-html", + "etag", + "fresh@2.0.0", + "http-errors", + "mime-types@3.0.1", + "ms@2.1.3", + "on-finished", + "range-parser", + "statuses" + ] + }, + "serve-static@1.16.2": { + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": [ + "encodeurl@2.0.0", + "escape-html", + "parseurl", + "send@0.19.0" + ] + }, + "serve-static@2.2.0": { + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "dependencies": [ + "encodeurl@2.0.0", + "escape-html", + "parseurl", + "send@1.2.0" + ] + }, + "setprototypeof@1.2.0": { + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command@2.0.0": { + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": [ + "shebang-regex" + ] + }, + "shebang-regex@3.0.0": { + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "side-channel-list@1.0.0": { + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": [ + "es-errors", + "object-inspect" + ] + }, + "side-channel-map@1.0.1": { + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": [ + "call-bound", + "es-errors", + "get-intrinsic", + "object-inspect" + ] + }, + "side-channel-weakmap@1.0.2": { + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": [ + "call-bound", + "es-errors", + "get-intrinsic", + "object-inspect", + "side-channel-map" + ] + }, + "side-channel@1.1.0": { + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dependencies": [ + "es-errors", + "object-inspect", + "side-channel-list", + "side-channel-map", + "side-channel-weakmap" + ] + }, + "statuses@2.0.1": { + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "strip-json-comments@3.1.1": { + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "supports-color@7.2.0": { + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": [ + "has-flag" + ] + }, + "toidentifier@1.0.1": { + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "type-check@0.4.0": { + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": [ + "prelude-ls" + ] + }, + "type-is@1.6.18": { + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": [ + "media-typer@0.3.0", + "mime-types@2.1.35" + ] + }, + "type-is@2.0.1": { + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "dependencies": [ + "content-type", + "media-typer@1.1.0", + "mime-types@3.0.1" + ] + }, + "unpipe@1.0.0": { + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "uri-js@4.4.1": { + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": [ + "punycode" + ] + }, + "utils-merge@1.0.1": { + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "vary@1.1.2": { + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "which@2.0.2": { + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": [ + "isexe" + ] + }, + "word-wrap@1.2.5": { + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==" + }, + "wrappy@1.0.2": { + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "ws@8.18.1": { + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==" + }, + "yocto-queue@0.1.0": { + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, + "zod-to-json-schema@3.24.5_zod@3.24.2": { + "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", + "dependencies": [ + "zod" + ] + }, + "zod@3.24.2": { + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==" + } + }, + "workspace": { + "dependencies": [ + "npm:@modelcontextprotocol/sdk@^1.8.0", + "npm:express@^4.21.2", + "npm:pyodide@~0.27.4", + "npm:zod@^3.24.2" + ] + } +} diff --git a/mcp-run-python/eslint.config.mjs b/mcp-run-python/eslint.config.mjs deleted file mode 100644 index 935f564ee9..0000000000 --- a/mcp-run-python/eslint.config.mjs +++ /dev/null @@ -1,4 +0,0 @@ -import eslint from '@eslint/js' -import tseslint from 'typescript-eslint' - -export default tseslint.config(eslint.configs.recommended, tseslint.configs.recommended) diff --git a/mcp-run-python/inline_python.js b/mcp-run-python/inline_python.js deleted file mode 100644 index 7b411a3387..0000000000 --- a/mcp-run-python/inline_python.js +++ /dev/null @@ -1,15 +0,0 @@ -// build dist/prepareEnvCode.js from src/prepare_env.py -const fs = require('fs') -const path = require('path') - -const src = path.resolve(__dirname, 'src/prepare_env.py') -const dst = path.resolve(__dirname, 'dist/prepareEnvCode.js') - -const pythonCode = fs.readFileSync(src, 'utf8').replace(/\\/g, '\\\\') -const jsCode = `// DO NOT EDIT THIS FILE DIRECTLY, INSTEAD RUN "npm run build" -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.preparePythonCode = \`${pythonCode}\` -` - -fs.writeFileSync(dst, jsCode, 'utf8') diff --git a/mcp-run-python/package-lock.json b/mcp-run-python/package-lock.json deleted file mode 100644 index 876ef3448f..0000000000 --- a/mcp-run-python/package-lock.json +++ /dev/null @@ -1,2774 +0,0 @@ -{ - "name": "@pydantic/mcp-run-python", - "version": "0.0.3", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@pydantic/mcp-run-python", - "version": "0.0.3", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.7.0", - "pyodide": "^0.27.2", - "zod": "^3.24.2" - }, - "bin": { - "mcp-run-python": "cli.js" - }, - "devDependencies": { - "@types/express": "^5.0.0", - "@types/node": "^22.13.10", - "eslint": "^9.22.0", - "prettier": "^3.5.3", - "typescript": "^5.8.2", - "typescript-eslint": "^8.26.1" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", - "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", - "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", - "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", - "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", - "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", - "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", - "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.12.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.7.0.tgz", - "integrity": "sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "cors": "^2.8.5", - "eventsource": "^3.0.2", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "pkce-challenge": "^4.1.0", - "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", - "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", - "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.13.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", - "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/qs": { - "version": "6.9.18", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", - "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz", - "integrity": "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.26.1", - "@typescript-eslint/type-utils": "8.26.1", - "@typescript-eslint/utils": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz", - "integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.26.1", - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/typescript-estree": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz", - "integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.1.tgz", - "integrity": "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "8.26.1", - "@typescript-eslint/utils": "8.26.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz", - "integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz", - "integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.1.tgz", - "integrity": "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.26.1", - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/typescript-estree": "8.26.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz", - "integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.26.1", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.1.0.tgz", - "integrity": "sha512-/hPxh61E+ll0Ujp24Ilm64cykicul1ypfwjVttduAiEdtnJFvLePSrIPk+HMImtNv5270wOGCb1Tns2rybMkoQ==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.5.2", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", - "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.2", - "@eslint/config-helpers": "^0.1.0", - "@eslint/core": "^0.12.0", - "@eslint/eslintrc": "^3.3.0", - "@eslint/js": "9.22.0", - "@eslint/plugin-kit": "^0.2.7", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.5.tgz", - "integrity": "sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", - "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.0.1.tgz", - "integrity": "sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.0.1", - "content-disposition": "^1.0.0", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "^1.2.1", - "debug": "4.3.6", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "^2.0.0", - "fresh": "2.0.0", - "http-errors": "2.0.0", - "merge-descriptors": "^2.0.0", - "methods": "~1.1.2", - "mime-types": "^3.0.0", - "on-finished": "2.4.1", - "once": "1.4.0", - "parseurl": "~1.3.3", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "router": "^2.0.0", - "safe-buffer": "5.2.1", - "send": "^1.1.0", - "serve-static": "^2.1.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "^2.0.0", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", - "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": "^4.11 || 5 || ^5.0.0-beta.1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", - "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", - "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.0.tgz", - "integrity": "sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.53.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkce-challenge": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz", - "integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pyodide": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.27.3.tgz", - "integrity": "sha512-6NwKEbPk0M3Wic2T1TCZijgZH9VE4RkHp1VGljS1sou0NjGdsmY2R/fG5oLmdDkjTRMI1iW7WYaY9pofX8gg1g==", - "license": "Apache-2.0", - "dependencies": { - "ws": "^8.5.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/router": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.1.0.tgz", - "integrity": "sha512-/m/NSLxeYEgWNtyC+WtNHCF7jbGxOibVWKnn+1Psff4dJGOfoXP+MuC/f2CwSmyiHdOIzYnYFp4W6GxWfekaLA==", - "license": "MIT", - "dependencies": { - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.1.0.tgz", - "integrity": "sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "destroy": "^1.2.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^0.5.2", - "http-errors": "^2.0.0", - "mime-types": "^2.1.35", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/send/node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.1.0.tgz", - "integrity": "sha512-A3We5UfEjG8Z7VkDv6uItWw6HY2bBSBJT1KtVESn6EOoOr2jAxNhxWCLY3jDE2WcuHXByWju74ck3ZgLwL8xmA==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-api-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", - "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.0.tgz", - "integrity": "sha512-gd0sGezQYCbWSbkZr75mln4YBidWUN60+devscpLF5mtRDUpiaTvKpBNrdaCvel1NdR2k6vclXybU5fBd2i+nw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.26.1.tgz", - "integrity": "sha512-t/oIs9mYyrwZGRpDv3g+3K6nZ5uhKEMt2oNmAPwaY4/ye0+EH4nXIPYNtkYFS6QHm+1DFg34DbglYBz5P9Xysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.26.1", - "@typescript-eslint/parser": "8.26.1", - "@typescript-eslint/utils": "8.26.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz", - "integrity": "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" - } - } - } -} diff --git a/mcp-run-python/package.json b/mcp-run-python/package.json deleted file mode 100644 index 0bb53a1292..0000000000 --- a/mcp-run-python/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@pydantic/mcp-run-python", - "version": "0.0.4", - "description": "MCP server to run Python code in a sandbox.", - "author": "Samuel Colvin", - "homepage": "https://github.com/pydantic/pydantic-ai/tree/main/mcp-run-python", - "bugs": "https://github.com/pydantic/pydantic-ai/issues", - "keywords": [ - "python", - "pydantic", - "sandbox", - "modelcontextprotocol", - "mcp" - ], - "main": "dist/index.js", - "license": "MIT", - "scripts": { - "format": "prettier --write -- .", - "lint": "eslint --max-warnings=0 src && prettier --check -- . && tsc --noEmit", - "prepare": "rm -rf dist && tsc && node inline_python.js", - "dev-sse": "npm run prepare && npx . sse", - "dev-stdio": "npm run prepare && npx . stdio", - "dev-warmup": "npm run prepare && npx . warmup" - }, - "bin": "./cli.js", - "files": [ - "cli.js", - "dist" - ], - "prettier": { - "singleQuote": true, - "semi": false, - "trailingComma": "all", - "tabWidth": 2, - "printWidth": 119, - "bracketSpacing": true - }, - "dependencies": { - "@modelcontextprotocol/sdk": "^1.7.0", - "pyodide": "^0.27.2", - "zod": "^3.24.2" - }, - "devDependencies": { - "@types/express": "^5.0.0", - "@types/node": "^22.13.10", - "eslint": "^9.22.0", - "prettier": "^3.5.3", - "typescript": "^5.8.2", - "typescript-eslint": "^8.26.1" - } -} diff --git a/mcp-run-python/pyproject.toml b/mcp-run-python/pyproject.toml index 59386a7d25..9bcf610d51 100644 --- a/mcp-run-python/pyproject.toml +++ b/mcp-run-python/pyproject.toml @@ -17,4 +17,4 @@ dev = [ ] [tool.uv.sources] -pydantic-graph = { workspace = true } +mcp-run-python = { workspace = true } diff --git a/mcp-run-python/src/index.ts b/mcp-run-python/src/index.ts deleted file mode 100644 index f8a065086c..0000000000 --- a/mcp-run-python/src/index.ts +++ /dev/null @@ -1,145 +0,0 @@ -import express, { Request, Response } from 'express' -import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js' -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' -import { SetLevelRequestSchema, LoggingLevel } from '@modelcontextprotocol/sdk/types.js' -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' -import { z } from 'zod' - -import { runCode, asXml } from './runCode.js' - -export async function main() { - const args = process.argv.slice(2) - if (args.length === 1 && args[0] === 'stdio') { - await runStdio() - } else if (args.length === 1 && args[0] === 'sse') { - runSse() - } else if (args.length === 1 && args[0] === 'warmup') { - await warmup() - } else { - console.error('Usage: npx @pydantic/mcp-run-python [stdio|sse|warmup]') - process.exit(1) - } -} - -/* - * Create an MCP server with the `run_python_code` tool registered. - */ -function createServer(): McpServer { - const server = new McpServer( - { - name: 'MCP Run Python', - version: '0.0.1', - }, - { - instructions: 'Call the "run_python_code" tool with the Python code to run.', - capabilities: { - logging: {}, - }, - }, - ) - - const toolDescription = `Tool to execute Python code and return stdout, stderr, and return value. - -The code may be async, and the value on the last line will be returned as the return value. - -The code will be executed with Python 3.12. - -Dependencies may be defined via PEP 723 script metadata, e.g. to install "pydantic", the script should start -with a comment of the form: - -# /// script -# dependencies = ['pydantic'] -# /// -` - - let setLogLevel: LoggingLevel = 'emergency' - - server.server.setRequestHandler(SetLevelRequestSchema, async (request) => { - setLogLevel = request.params.level - return {} - }) - - server.tool( - 'run_python_code', - toolDescription, - { python_code: z.string().describe('Python code to run') }, - async ({ python_code }: { python_code: string }) => { - const logPromises: Promise[] = [] - const result = await runCode([{ name: 'main.py', content: python_code, active: true }], (level, data) => { - if (LogLevels.indexOf(level) >= LogLevels.indexOf(setLogLevel)) { - logPromises.push(server.server.sendLoggingMessage({ level, data })) - } - }) - await Promise.all(logPromises) - return { - content: [{ type: 'text', text: asXml(result) }], - } - }, - ) - return server -} - -/* - * Run the MCP server using the SSE transport, e.g. over HTTP. - */ -function runSse() { - const mcpServer = createServer() - const app = express() - const transports: { [sessionId: string]: SSEServerTransport } = {} - - app.get('/sse', async (_: Request, res: Response) => { - const transport = new SSEServerTransport('/messages', res) - transports[transport.sessionId] = transport - res.on('close', () => { - delete transports[transport.sessionId] - }) - await mcpServer.connect(transport) - }) - - app.post('/messages', async (req: Request, res: Response) => { - const sessionId = req.query.sessionId as string - const transport = transports[sessionId] - if (transport) { - await transport.handlePostMessage(req, res) - } else { - res.status(400).send(`No transport found for sessionId '${sessionId}'`) - } - }) - - const port = process.env.PORT ? parseInt(process.env.PORT) : 3001 - const host = process.env.HOST || 'localhost' - console.log(`Running MCP server with SSE transport on ${host}:${port}`) - app.listen(port, host) -} - -/* - * Run the MCP server using the Stdio transport. - */ -async function runStdio() { - const mcpServer = createServer() - const transport = new StdioServerTransport() - await mcpServer.connect(transport) -} - -/* - * Run pyodide to download packages which can otherwise interrupt the server - */ -async function warmup() { - console.error('Running warmup script...') - const code = ` -import numpy -a = numpy.array([1, 2, 3]) -print('numpy array:', a) -a -` - const result = await runCode([{ name: 'warmup.py', content: code, active: true }], (level, data) => - // use warn to avoid recursion since console.log is patched in runCode - console.error(`${level}: ${data}`), - ) - console.log('Tool return value:') - console.log(asXml(result)) - console.log('\nwarmup successful 🎉') -} - -// list of log levels to use for level comparison -const LogLevels: LoggingLevel[] = ['debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency'] diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts new file mode 100644 index 0000000000..4ac24e5d1c --- /dev/null +++ b/mcp-run-python/src/main.ts @@ -0,0 +1,170 @@ +import express, { type Request, type Response } from "express"; +import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + type LoggingLevel, + SetLevelRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; + +import { asXml, runCode } from "./runCode.ts"; + +export async function main() { + const { args } = Deno; + if (args.length === 1 && args[0] === "stdio") { + await runStdio(); + } else if (args.length === 1 && args[0] === "sse") { + runSse(); + } else if (args.length === 1 && args[0] === "warmup") { + await warmup(); + } else { + console.error("Usage: npx @pydantic/mcp-run-python [stdio|sse|warmup]"); + Deno.exit(1); + } +} + +/* + * Create an MCP server with the `run_python_code` tool registered. + */ +function createServer(): McpServer { + const server = new McpServer( + { + name: "MCP Run Python", + version: "0.0.1", + }, + { + instructions: + 'Call the "run_python_code" tool with the Python code to run.', + capabilities: { + logging: {}, + }, + }, + ); + + const toolDescription = + `Tool to execute Python code and return stdout, stderr, and return value. + +The code may be async, and the value on the last line will be returned as the return value. + +The code will be executed with Python 3.12. + +Dependencies may be defined via PEP 723 script metadata, e.g. to install "pydantic", the script should start +with a comment of the form: + +# /// script +# dependencies = ['pydantic'] +# /// +`; + + let setLogLevel: LoggingLevel = "emergency"; + + server.server.setRequestHandler(SetLevelRequestSchema, (request) => { + setLogLevel = request.params.level; + return {}; + }); + + server.tool( + "run_python_code", + toolDescription, + { python_code: z.string().describe("Python code to run") }, + async ({ python_code }: { python_code: string }) => { + const logPromises: Promise[] = []; + const result = await runCode([{ + name: "main.py", + content: python_code, + active: true, + }], (level, data) => { + if (LogLevels.indexOf(level) >= LogLevels.indexOf(setLogLevel)) { + logPromises.push(server.server.sendLoggingMessage({ level, data })); + } + }); + await Promise.all(logPromises); + return { + content: [{ type: "text", text: asXml(result) }], + }; + }, + ); + return server; +} + +/* + * Run the MCP server using the SSE transport, e.g. over HTTP. + */ +function runSse() { + const mcpServer = createServer(); + const app = express(); + const transports: { [sessionId: string]: SSEServerTransport } = {}; + + app.get("/sse", async (_: Request, res: Response) => { + const transport = new SSEServerTransport("/messages", res); + transports[transport.sessionId] = transport; + res.on("close", () => { + delete transports[transport.sessionId]; + }); + await mcpServer.connect(transport); + }); + + app.post("/messages", async (req: Request, res: Response) => { + const sessionId = req.query.sessionId as string; + const transport = transports[sessionId]; + if (transport) { + await transport.handlePostMessage(req, res); + } else { + res.status(400).send(`No transport found for sessionId '${sessionId}'`); + } + }); + + // const port = Deno.env.PORT ? parseInt(Deno.env.PORT) : 3001; + const port = 3001; + // const host = Deno.env.HOST || "localhost"; + const host = "localhost"; + console.log(`Running MCP server with SSE transport on ${host}:${port}`); + app.listen(port, host); +} + +/* + * Run the MCP server using the Stdio transport. + */ +async function runStdio() { + const mcpServer = createServer(); + const transport = new StdioServerTransport(); + await mcpServer.connect(transport); +} + +/* + * Run pyodide to download packages which can otherwise interrupt the server + */ +async function warmup() { + console.error("Running warmup script..."); + const code = ` +import numpy +a = numpy.array([1, 2, 3]) +print('numpy array:', a) +a +`; + const result = await runCode([{ + name: "warmup.py", + content: code, + active: true, + }], (level, data) => + // use warn to avoid recursion since console.log is patched in runCode + console.error(`${level}: ${data}`)); + console.log("Tool return value:"); + console.log(asXml(result)); + console.log("\nwarmup successful 🎉"); +} + +// list of log levels to use for level comparison +const LogLevels: LoggingLevel[] = [ + "debug", + "info", + "notice", + "warning", + "error", + "critical", + "alert", + "emergency", +]; + +await main(); diff --git a/mcp-run-python/src/prepareEnvCode.d.ts b/mcp-run-python/src/prepareEnvCode.d.ts deleted file mode 100644 index 74d66bc9ac..0000000000 --- a/mcp-run-python/src/prepareEnvCode.d.ts +++ /dev/null @@ -1 +0,0 @@ -export const preparePythonCode: string diff --git a/mcp-run-python/src/prepare_env.py b/mcp-run-python/src/prepareEnvCode.ts similarity index 98% rename from mcp-run-python/src/prepare_env.py rename to mcp-run-python/src/prepareEnvCode.ts index fa9d31952f..8d71400127 100644 --- a/mcp-run-python/src/prepare_env.py +++ b/mcp-run-python/src/prepareEnvCode.ts @@ -1,3 +1,4 @@ +export const preparePythonCode = ` """Logic for installing dependencies in Pyodide. Mostly taken from https://github.com/pydantic/pydantic.run/blob/main/src/frontend/src/prepare_env.py @@ -68,7 +69,7 @@ async def prepare_env(files: list[File]) -> Success | Error: except Exception: with open(logs_filename) as f: logs = f.read() - return Error(message=f'{logs}\n{traceback.format_exc()}') + return Error(message=f'{logs} {traceback.format_exc()}') return Success(dependencies=dependencies) @@ -198,3 +199,4 @@ def _find_imports_to_install(imports: list[str]) -> Iterable[str]: yield package_name elif '.' not in module: yield module +`; diff --git a/mcp-run-python/src/runCode.ts b/mcp-run-python/src/runCode.ts index a30bf37cab..acc2b06f3c 100644 --- a/mcp-run-python/src/runCode.ts +++ b/mcp-run-python/src/runCode.ts @@ -1,12 +1,12 @@ /* eslint @typescript-eslint/no-explicit-any: off */ -import { loadPyodide } from 'pyodide' -import { preparePythonCode } from './prepareEnvCode.js' -import type { LoggingLevel } from '@modelcontextprotocol/sdk/types.js' +import { loadPyodide } from "pyodide"; +import { preparePythonCode } from "./prepareEnvCode.ts"; +import type { LoggingLevel } from "@modelcontextprotocol/sdk/types.js"; export interface CodeFile { - name: string - content: string - active: boolean + name: string; + content: string; + active: boolean; } export async function runCode( @@ -14,150 +14,158 @@ export async function runCode( log: (level: LoggingLevel, data: string) => void, ): Promise { // remove once https://github.com/pyodide/pyodide/pull/5514 is released - const realConsoleLog = console.log - console.log = (...args: any[]) => log('debug', args.join(' ')) + const realConsoleLog = console.log; + // deno-lint-ignore no-explicit-any + console.log = (...args: any[]) => log("debug", args.join(" ")); - const output: string[] = [] + const output: string[] = []; const pyodide = await loadPyodide({ stdout: (msg) => { - log('info', msg) - output.push(msg) + log("info", msg); + output.push(msg); }, stderr: (msg) => { - log('warning', msg) - output.push(msg) + log("warning", msg); + output.push(msg); }, - }) + }); // see https://github.com/pyodide/pyodide/discussions/5512 - const origLoadPackage = pyodide.loadPackage + const origLoadPackage = pyodide.loadPackage; pyodide.loadPackage = (pkgs, options) => origLoadPackage(pkgs, { // stop pyodide printing to stdout/stderr - messageCallback: (msg: string) => log('debug', `loadPackage: ${msg}`), + messageCallback: (msg: string) => log("debug", `loadPackage: ${msg}`), errorCallback: (msg: string) => { - log('error', `loadPackage: ${msg}`) - output.push(`install error: ${msg}`) + log("error", `loadPackage: ${msg}`); + output.push(`install error: ${msg}`); }, ...options, - }) + }); - await pyodide.loadPackage(['micropip', 'pydantic']) - const sys = pyodide.pyimport('sys') + await pyodide.loadPackage(["micropip", "pydantic"]); + const sys = pyodide.pyimport("sys"); - const dirPath = '/tmp/mcp_run_python' - sys.path.append(dirPath) - const pathlib = pyodide.pyimport('pathlib') - pathlib.Path(dirPath).mkdir() - const moduleName = '_prepare_env' + const dirPath = "/tmp/mcp_run_python"; + sys.path.append(dirPath); + const pathlib = pyodide.pyimport("pathlib"); + pathlib.Path(dirPath).mkdir(); + const moduleName = "_prepare_env"; - pathlib.Path(`${dirPath}/${moduleName}.py`).write_text(preparePythonCode) + pathlib.Path(`${dirPath}/${moduleName}.py`).write_text(preparePythonCode); - const preparePyEnv: PreparePyEnv = pyodide.pyimport(moduleName) + const preparePyEnv: PreparePyEnv = pyodide.pyimport(moduleName); - const prepareStatus = await preparePyEnv.prepare_env(pyodide.toPy(files)) + const prepareStatus = await preparePyEnv.prepare_env(pyodide.toPy(files)); - let runResult: RunSuccess | RunError - if (prepareStatus.kind == 'error') { + let runResult: RunSuccess | RunError; + if (prepareStatus.kind == "error") { runResult = { - status: 'install-error', + status: "install-error", output, error: prepareStatus.message, - } + }; } else { - const { dependencies } = prepareStatus - const activeFile = files.find((f) => f.active)! || files[0] + const { dependencies } = prepareStatus; + const activeFile = files.find((f) => f.active)! || files[0]; try { const rawValue = await pyodide.runPythonAsync(activeFile.content, { - globals: pyodide.toPy({ __name__: '__main__' }), + globals: pyodide.toPy({ __name__: "__main__" }), filename: activeFile.name, - }) + }); runResult = { - status: 'success', + status: "success", dependencies, output, returnValueJson: preparePyEnv.dump_json(rawValue), - } + }; } catch (err) { runResult = { - status: 'run-error', + status: "run-error", dependencies, output, error: formatError(err), - } + }; } } - sys.stdout.flush() - sys.stderr.flush() - console.log = realConsoleLog - return runResult + sys.stdout.flush(); + sys.stderr.flush(); + console.log = realConsoleLog; + return runResult; } interface RunSuccess { - status: 'success' + status: "success"; // we could record stdout and stderr separately, but I suspect simplicity is more important - output: string[] - dependencies: string[] - returnValueJson: string | null + output: string[]; + dependencies: string[]; + returnValueJson: string | null; } interface RunError { - status: 'install-error' | 'run-error' - output: string[] - dependencies?: string[] - error: string + status: "install-error" | "run-error"; + output: string[]; + dependencies?: string[]; + error: string; } export function asXml(runResult: RunSuccess | RunError): string { - const xml = [`${runResult.status}`] + const xml = [`${runResult.status}`]; if (runResult.dependencies?.length) { - xml.push(`${JSON.stringify(runResult.dependencies)}`) + xml.push( + `${JSON.stringify(runResult.dependencies)}`, + ); } if (runResult.output.length) { - xml.push('') - const escapeXml = escapeClosing('output') - xml.push(...runResult.output.map(escapeXml)) - xml.push('') + xml.push(""); + const escapeXml = escapeClosing("output"); + xml.push(...runResult.output.map(escapeXml)); + xml.push(""); } - if (runResult.status == 'success') { + if (runResult.status == "success") { if (runResult.returnValueJson) { - xml.push('') - xml.push(escapeClosing('return_value')(runResult.returnValueJson)) - xml.push('') + xml.push(""); + xml.push(escapeClosing("return_value")(runResult.returnValueJson)); + xml.push(""); } } else { - xml.push('') - xml.push(escapeClosing('error')(runResult.error)) - xml.push('') + xml.push(""); + xml.push(escapeClosing("error")(runResult.error)); + xml.push(""); } - return xml.join('\n') + return xml.join("\n"); } function escapeClosing(closingTag: string): (str: string) => string { - const regex = new RegExp(`)?`, 'gi') + const regex = new RegExp(`)?`, "gi"); const onMatch = (match: string) => { - return match.replace(//g, '>') - } - return (str) => str.replace(regex, onMatch) + return match.replace(//g, ">"); + }; + return (str) => str.replace(regex, onMatch); } +// deno-lint-ignore no-explicit-any function formatError(err: any): string { - let errStr = err.toString() - errStr = errStr.replace(/^PythonError: +/, '') + let errStr = err.toString(); + errStr = errStr.replace(/^PythonError: +/, ""); // remove frames from inside pyodide - errStr = errStr.replace(/ {2}File "\/lib\/python\d+\.zip\/_pyodide\/.*\n {4}.*\n(?: {4,}\^+\n)?/g, '') - return errStr + errStr = errStr.replace( + / {2}File "\/lib\/python\d+\.zip\/_pyodide\/.*\n {4}.*\n(?: {4,}\^+\n)?/g, + "", + ); + return errStr; } interface PrepareSuccess { - kind: 'success' - dependencies: string[] + kind: "success"; + dependencies: string[]; } interface PrepareError { - kind: 'error' - message: string + kind: "error"; + message: string; } interface PreparePyEnv { - prepare_env: (files: CodeFile[]) => Promise - dump_json: (value: any) => string | null + prepare_env: (files: CodeFile[]) => Promise; + // deno-lint-ignore no-explicit-any + dump_json: (value: any) => string | null; } diff --git a/mcp-run-python/tsconfig.json b/mcp-run-python/tsconfig.json deleted file mode 100644 index 40e9718cd9..0000000000 --- a/mcp-run-python/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "lib": ["esnext", "dom"], - "types": ["node"], - "outDir": "dist", - "module": "nodenext", - "moduleResolution": "nodenext", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} From 5a6d5d3d5aaa85f1a791bdc0ff6a95594a3bc116 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 09:31:46 +0100 Subject: [PATCH 02/15] switch to node:htp --- mcp-run-python/README.md | 10 +++++-- mcp-run-python/deno.json | 4 +-- mcp-run-python/src/main.ts | 58 +++++++++++++++++++++++++------------- 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/mcp-run-python/README.md b/mcp-run-python/README.md index 1a8d4a4713..12f588bec7 100644 --- a/mcp-run-python/README.md +++ b/mcp-run-python/README.md @@ -7,10 +7,16 @@ The code is executed using [pyodide](https://pyodide.org) in [deno](https://deno.com/) and is therefore isolated from the rest of the operating system. -The server can be run with just npx thus: +The server can be run with [deno](https://deno.com/) installed: ```bash -npx @pydantic/mcp-run-python [stdio|sse] +deno run \ + --allow-net \ + --allow-read=node_modules \ + --allow-write=node_modules \ + --allow-env=NO_DEPRECATION,TRACE_DEPRECATION \ + jsr:@pydantic/mcp-run-python \ + [stdio|sse] ``` where: diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json index c6fdfd5f95..3cc801f1de 100644 --- a/mcp-run-python/deno.json +++ b/mcp-run-python/deno.json @@ -1,10 +1,10 @@ { "name": "@pydantic/mcp-run-python", - "version": "0.0.5", + "version": "0.0.6", "license": "MIT", "nodeModulesDir": "auto", "exports": { - ".": "./dist/index.js" + ".": "./src/main.ts" }, "tasks": { "lint-format": "deno fmt && deno lint && deno check src" diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index 4ac24e5d1c..0d65ce525f 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -1,4 +1,4 @@ -import express, { type Request, type Response } from "express"; +import http from "node:http"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { @@ -93,34 +93,52 @@ with a comment of the form: */ function runSse() { const mcpServer = createServer(); - const app = express(); const transports: { [sessionId: string]: SSEServerTransport } = {}; - app.get("/sse", async (_: Request, res: Response) => { - const transport = new SSEServerTransport("/messages", res); - transports[transport.sessionId] = transport; - res.on("close", () => { - delete transports[transport.sessionId]; - }); - await mcpServer.connect(transport); - }); + const server = http.createServer(async (req, res) => { + const url = new URL( + req.url ?? "", + `http://${req.headers.host ?? "unknown"}`, + ); + console.log({ url, method: req.method }); + let pathMatch = false; + function match(methods: string[], path: string): boolean { + if (url.pathname === path) { + pathMatch = true; + return methods.includes(req.method!); + } + return false; + } - app.post("/messages", async (req: Request, res: Response) => { - const sessionId = req.query.sessionId as string; - const transport = transports[sessionId]; - if (transport) { - await transport.handlePostMessage(req, res); + if (match(["GET", "POST"], "/sse")) { + const transport = new SSEServerTransport("/sse", res); + transports[transport.sessionId] = transport; + res.on("close", () => { + delete transports[transport.sessionId]; + }); + await mcpServer.connect(transport); + } else if (match(["POST"], "/messages")) { + const sessionId = url.searchParams.get("sessionId") ?? ""; + const transport = transports[sessionId]; + if (transport) { + await transport.handlePostMessage(req, res); + } else { + res.setHeader("Content-Type", "text/plain"); + res.statusCode = 400; + res.end(`No transport found for sessionId '${sessionId}'`); + } } else { - res.status(400).send(`No transport found for sessionId '${sessionId}'`); + res.setHeader("Content-Type", "text/plain"); + res.statusCode = pathMatch ? 405 : 404; + res.end(pathMatch ? "Method not allowed\n" : "Page not found\n"); } }); // const port = Deno.env.PORT ? parseInt(Deno.env.PORT) : 3001; const port = 3001; - // const host = Deno.env.HOST || "localhost"; - const host = "localhost"; - console.log(`Running MCP server with SSE transport on ${host}:${port}`); - app.listen(port, host); + server.listen(port, () => { + console.log(`Running MCP server with SSE transport on port ${port}`); + }); } /* From b2bd194e58def64192957cd0403436034af89348 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 11:49:53 +0100 Subject: [PATCH 03/15] fixing tests and cleanup --- .github/workflows/ci.yml | 35 ++-- mcp-run-python/README.md | 20 +- mcp-run-python/deno.json | 4 +- mcp-run-python/deno.lock | 283 ++++++----------------------- mcp-run-python/src/main.ts | 25 ++- mcp-run-python/test_mcp_servers.py | 69 +++---- 6 files changed, 142 insertions(+), 294 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2649388ea5..a31e223be0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ on: env: COLUMNS: 150 UV_PYTHON: 3.12 - UV_FROZEN: '1' + UV_FROZEN: "1" permissions: contents: read @@ -29,10 +29,9 @@ jobs: - name: Install dependencies run: uv sync --all-extras --all-packages --group lint - - uses: actions/setup-node@v4 - - - run: npm install - working-directory: mcp-run-python + - uses: denoland/setup-deno@v2 + with: + deno-version: v2.x - uses: pre-commit/action@v3.0.0 with: @@ -233,21 +232,27 @@ jobs: with: enable-cache: true - - uses: actions/setup-node@v4 - - - run: npm install - working-directory: mcp-run-python - - - run: npm run lint - working-directory: mcp-run-python + - uses: denoland/setup-deno@v2 + with: + deno-version: v2.x - - run: npm run prepare + - run: | + deno run format + deno run lint + deno run check working-directory: mcp-run-python - run: uv run --package mcp-run-python pytest mcp-run-python -v - # check npx works - - run: npx . warmup + # check warmup works + - run: > + deno run + -N + -R=node_modules + -W=node_modules + --node-modules-dir=auto + src/main.ts + warmup working-directory: mcp-run-python # https://github.com/marketplace/actions/alls-green#why used for branch protection checks diff --git a/mcp-run-python/README.md b/mcp-run-python/README.md index 12f588bec7..c8b09b0c5f 100644 --- a/mcp-run-python/README.md +++ b/mcp-run-python/README.md @@ -7,23 +7,29 @@ The code is executed using [pyodide](https://pyodide.org) in [deno](https://deno.com/) and is therefore isolated from the rest of the operating system. -The server can be run with [deno](https://deno.com/) installed: +The server can be run with [deno](https://deno.com/) installed using: ```bash deno run \ - --allow-net \ - --allow-read=node_modules \ - --allow-write=node_modules \ - --allow-env=NO_DEPRECATION,TRACE_DEPRECATION \ + -N -R=node_modules -W=node_modules \ + --node-modules-dir=auto \ jsr:@pydantic/mcp-run-python \ - [stdio|sse] + [stdio|sse|warmup] ``` where: +- `-N -R=node_modules -W=node_modules` (alias of + `--allow-net --allow-read=node_modules --allow-write=node_modules`) allows + network access and read+write access to `./node_modules`. These are required + so pyodide can download and cache the Python standard library and packages +- `--node-modules-dir=auto` tells deno to use a local `node_modules` directory - `stdio` runs the server with the [Stdio MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) — suitable for running the process as a subprocess locally -- and `sse` runs the server with the +- `sse` runs the server with the [SSE MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) — running the server as an HTTP server to connect locally or remotely +- `warmup` will run a minimal Python script to download and cache the Python + standard library. This is also useful to check the server is running + correctly. diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json index 3cc801f1de..0a30945dd8 100644 --- a/mcp-run-python/deno.json +++ b/mcp-run-python/deno.json @@ -1,6 +1,6 @@ { "name": "@pydantic/mcp-run-python", - "version": "0.0.6", + "version": "0.0.7", "license": "MIT", "nodeModulesDir": "auto", "exports": { @@ -11,7 +11,7 @@ }, "imports": { "@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.8.0", - "express": "npm:express@^4.21.2", + "@std/cli": "jsr:@std/cli@^1.0.15", "pyodide": "npm:pyodide@^0.27.4", "zod": "npm:zod@^3.24.2" } diff --git a/mcp-run-python/deno.lock b/mcp-run-python/deno.lock index 09ea5ebdb6..25c722fada 100644 --- a/mcp-run-python/deno.lock +++ b/mcp-run-python/deno.lock @@ -1,12 +1,18 @@ { "version": "4", "specifiers": { + "jsr:@std/cli@*": "1.0.15", + "jsr:@std/cli@^1.0.15": "1.0.15", "npm:@modelcontextprotocol/sdk@^1.8.0": "1.8.0_express@5.1.0_zod@3.24.2", "npm:eslint@*": "9.23.0", - "npm:express@^4.21.2": "4.21.2", "npm:pyodide@~0.27.4": "0.27.4", "npm:zod@^3.24.2": "3.24.2" }, + "jsr": { + "@std/cli@1.0.15": { + "integrity": "e79ba3272ec710ca44d8342a7688e6288b0b88802703f3264184b52893d5e93f" + } + }, "npm": { "@eslint-community/eslint-utils@4.5.1_eslint@9.23.0": { "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", @@ -22,7 +28,7 @@ "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "dependencies": [ "@eslint/object-schema", - "debug@4.4.0", + "debug", "minimatch" ] }, @@ -39,7 +45,7 @@ "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dependencies": [ "ajv", - "debug@4.4.0", + "debug", "espree", "globals", "ignore", @@ -88,10 +94,10 @@ "cors", "cross-spawn", "eventsource", - "express@5.1.0", + "express", "express-rate-limit", "pkce-challenge", - "raw-body@3.0.0", + "raw-body", "zod", "zod-to-json-schema" ] @@ -102,18 +108,11 @@ "@types/json-schema@7.0.15": { "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, - "accepts@1.3.8": { - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": [ - "mime-types@2.1.35", - "negotiator@0.6.3" - ] - }, "accepts@2.0.0": { "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dependencies": [ - "mime-types@3.0.1", - "negotiator@1.0.0" + "mime-types", + "negotiator" ] }, "acorn-jsx@5.3.2_acorn@8.14.1": { @@ -143,41 +142,21 @@ "argparse@2.0.1": { "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "array-flatten@1.1.1": { - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, "balanced-match@1.0.2": { "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "body-parser@1.20.3": { - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "dependencies": [ - "bytes", - "content-type", - "debug@2.6.9", - "depd", - "destroy", - "http-errors", - "iconv-lite@0.4.24", - "on-finished", - "qs@6.13.0", - "raw-body@2.5.2", - "type-is@1.6.18", - "unpipe" - ] - }, "body-parser@2.2.0": { "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "dependencies": [ "bytes", "content-type", - "debug@4.4.0", + "debug", "http-errors", - "iconv-lite@0.6.3", + "iconv-lite", "on-finished", - "qs@6.14.0", - "raw-body@3.0.0", - "type-is@2.0.1" + "qs", + "raw-body", + "type-is" ] }, "brace-expansion@1.1.11": { @@ -226,12 +205,6 @@ "concat-map@0.0.1": { "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "content-disposition@0.5.4": { - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": [ - "safe-buffer" - ] - }, "content-disposition@1.0.0": { "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "dependencies": [ @@ -241,9 +214,6 @@ "content-type@1.0.5": { "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, - "cookie-signature@1.0.6": { - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, "cookie-signature@1.2.2": { "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==" }, @@ -265,16 +235,10 @@ "which" ] }, - "debug@2.6.9": { - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": [ - "ms@2.0.0" - ] - }, "debug@4.4.0": { "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dependencies": [ - "ms@2.1.3" + "ms" ] }, "deep-is@0.1.4": { @@ -283,9 +247,6 @@ "depd@2.0.0": { "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, - "destroy@1.2.0": { - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, "dunder-proto@1.0.1": { "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dependencies": [ @@ -297,9 +258,6 @@ "ee-first@1.1.1": { "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, - "encodeurl@1.0.2": { - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, "encodeurl@2.0.0": { "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, @@ -353,7 +311,7 @@ "ajv", "chalk", "cross-spawn", - "debug@4.4.0", + "debug", "escape-string-regexp", "eslint-scope", "eslint-visitor-keys@4.2.0", @@ -415,74 +373,38 @@ "express-rate-limit@7.5.0_express@5.1.0": { "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", "dependencies": [ - "express@5.1.0" - ] - }, - "express@4.21.2": { - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "dependencies": [ - "accepts@1.3.8", - "array-flatten", - "body-parser@1.20.3", - "content-disposition@0.5.4", - "content-type", - "cookie", - "cookie-signature@1.0.6", - "debug@2.6.9", - "depd", - "encodeurl@2.0.0", - "escape-html", - "etag", - "finalhandler@1.3.1", - "fresh@0.5.2", - "http-errors", - "merge-descriptors@1.0.3", - "methods", - "on-finished", - "parseurl", - "path-to-regexp@0.1.12", - "proxy-addr", - "qs@6.13.0", - "range-parser", - "safe-buffer", - "send@0.19.0", - "serve-static@1.16.2", - "setprototypeof", - "statuses", - "type-is@1.6.18", - "utils-merge", - "vary" + "express" ] }, "express@5.1.0": { "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "dependencies": [ - "accepts@2.0.0", - "body-parser@2.2.0", - "content-disposition@1.0.0", + "accepts", + "body-parser", + "content-disposition", "content-type", "cookie", - "cookie-signature@1.2.2", - "debug@4.4.0", - "encodeurl@2.0.0", + "cookie-signature", + "debug", + "encodeurl", "escape-html", "etag", - "finalhandler@2.1.0", - "fresh@2.0.0", + "finalhandler", + "fresh", "http-errors", - "merge-descriptors@2.0.0", - "mime-types@3.0.1", + "merge-descriptors", + "mime-types", "on-finished", "once", "parseurl", "proxy-addr", - "qs@6.14.0", + "qs", "range-parser", "router", - "send@1.2.0", - "serve-static@2.2.0", + "send", + "serve-static", "statuses", - "type-is@2.0.1", + "type-is", "vary" ] }, @@ -501,23 +423,11 @@ "flat-cache" ] }, - "finalhandler@1.3.1": { - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "dependencies": [ - "debug@2.6.9", - "encodeurl@2.0.0", - "escape-html", - "on-finished", - "parseurl", - "statuses", - "unpipe" - ] - }, "finalhandler@2.1.0": { "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "dependencies": [ - "debug@4.4.0", - "encodeurl@2.0.0", + "debug", + "encodeurl", "escape-html", "on-finished", "parseurl", @@ -544,9 +454,6 @@ "forwarded@0.2.0": { "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, - "fresh@0.5.2": { - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, "fresh@2.0.0": { "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==" }, @@ -609,12 +516,6 @@ "toidentifier" ] }, - "iconv-lite@0.4.24": { - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": [ - "safer-buffer" - ] - }, "iconv-lite@0.6.3": { "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dependencies": [ @@ -695,60 +596,33 @@ "math-intrinsics@1.1.0": { "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, - "media-typer@0.3.0": { - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, "media-typer@1.1.0": { "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" }, - "merge-descriptors@1.0.3": { - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" - }, "merge-descriptors@2.0.0": { "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==" }, - "methods@1.1.2": { - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "mime-db@1.52.0": { - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, "mime-db@1.54.0": { "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==" }, - "mime-types@2.1.35": { - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": [ - "mime-db@1.52.0" - ] - }, "mime-types@3.0.1": { "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dependencies": [ - "mime-db@1.54.0" + "mime-db" ] }, - "mime@1.6.0": { - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, "minimatch@3.1.2": { "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": [ "brace-expansion" ] }, - "ms@2.0.0": { - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "ms@2.1.3": { "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "natural-compare@1.4.0": { "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, - "negotiator@0.6.3": { - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, "negotiator@1.0.0": { "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==" }, @@ -808,9 +682,6 @@ "path-key@3.1.1": { "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, - "path-to-regexp@0.1.12": { - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" - }, "path-to-regexp@8.2.0": { "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==" }, @@ -836,12 +707,6 @@ "ws" ] }, - "qs@6.13.0": { - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": [ - "side-channel" - ] - }, "qs@6.14.0": { "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "dependencies": [ @@ -851,21 +716,12 @@ "range-parser@1.2.1": { "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, - "raw-body@2.5.2": { - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": [ - "bytes", - "http-errors", - "iconv-lite@0.4.24", - "unpipe" - ] - }, "raw-body@3.0.0": { "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", "dependencies": [ "bytes", "http-errors", - "iconv-lite@0.6.3", + "iconv-lite", "unpipe" ] }, @@ -875,11 +731,11 @@ "router@2.2.0": { "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dependencies": [ - "debug@4.4.0", + "debug", "depd", "is-promise", "parseurl", - "path-to-regexp@8.2.0" + "path-to-regexp" ] }, "safe-buffer@5.2.1": { @@ -888,56 +744,29 @@ "safer-buffer@2.1.2": { "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "send@0.19.0": { - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dependencies": [ - "debug@2.6.9", - "depd", - "destroy", - "encodeurl@1.0.2", - "escape-html", - "etag", - "fresh@0.5.2", - "http-errors", - "mime", - "ms@2.1.3", - "on-finished", - "range-parser", - "statuses" - ] - }, "send@1.2.0": { "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "dependencies": [ - "debug@4.4.0", - "encodeurl@2.0.0", + "debug", + "encodeurl", "escape-html", "etag", - "fresh@2.0.0", + "fresh", "http-errors", - "mime-types@3.0.1", - "ms@2.1.3", + "mime-types", + "ms", "on-finished", "range-parser", "statuses" ] }, - "serve-static@1.16.2": { - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "dependencies": [ - "encodeurl@2.0.0", - "escape-html", - "parseurl", - "send@0.19.0" - ] - }, "serve-static@2.2.0": { "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "dependencies": [ - "encodeurl@2.0.0", + "encodeurl", "escape-html", "parseurl", - "send@1.2.0" + "send" ] }, "setprototypeof@1.2.0": { @@ -1009,19 +838,12 @@ "prelude-ls" ] }, - "type-is@1.6.18": { - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": [ - "media-typer@0.3.0", - "mime-types@2.1.35" - ] - }, "type-is@2.0.1": { "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "dependencies": [ "content-type", - "media-typer@1.1.0", - "mime-types@3.0.1" + "media-typer", + "mime-types" ] }, "unpipe@1.0.0": { @@ -1033,9 +855,6 @@ "punycode" ] }, - "utils-merge@1.0.1": { - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, "vary@1.1.2": { "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, @@ -1069,8 +888,8 @@ }, "workspace": { "dependencies": [ + "jsr:@std/cli@^1.0.15", "npm:@modelcontextprotocol/sdk@^1.8.0", - "npm:express@^4.21.2", "npm:pyodide@~0.27.4", "npm:zod@^3.24.2" ] diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index 0d65ce525f..d8a1a66707 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -1,4 +1,5 @@ import http from "node:http"; +import { parseArgs } from "@std/cli/parse-args"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { @@ -14,12 +15,25 @@ export async function main() { const { args } = Deno; if (args.length === 1 && args[0] === "stdio") { await runStdio(); - } else if (args.length === 1 && args[0] === "sse") { - runSse(); + } else if (args.length >= 1 && args[0] === "sse") { + const flags = parseArgs(Deno.args, { + string: ["port"], + default: { port: "3001" }, + }); + const port = parseInt(flags.port); + runSse(port); } else if (args.length === 1 && args[0] === "warmup") { await warmup(); } else { - console.error("Usage: npx @pydantic/mcp-run-python [stdio|sse|warmup]"); + console.error( + `\ +Invalid arguments. + +Usage: deno run -N -R=node_modules -W=node_modules --node-modules-dir=auto jsr:@pydantic/mcp-run-python [stdio|sse|warmup] + +options: + --port Port to run the SSE server on (default: 3001)`, + ); Deno.exit(1); } } @@ -55,6 +69,7 @@ with a comment of the form: # /// script # dependencies = ['pydantic'] # /// +print('python code here') `; let setLogLevel: LoggingLevel = "emergency"; @@ -91,7 +106,7 @@ with a comment of the form: /* * Run the MCP server using the SSE transport, e.g. over HTTP. */ -function runSse() { +function runSse(port: number) { const mcpServer = createServer(); const transports: { [sessionId: string]: SSEServerTransport } = {}; @@ -134,8 +149,6 @@ function runSse() { } }); - // const port = Deno.env.PORT ? parseInt(Deno.env.PORT) : 3001; - const port = 3001; server.listen(port, () => { console.log(`Running MCP server with SSE transport on port ${port}`); }); diff --git a/mcp-run-python/test_mcp_servers.py b/mcp-run-python/test_mcp_servers.py index 5e77b55618..dc74138701 100644 --- a/mcp-run-python/test_mcp_servers.py +++ b/mcp-run-python/test_mcp_servers.py @@ -1,23 +1,26 @@ from __future__ import annotations as _annotations -import asyncio -import os -import subprocess from collections.abc import AsyncIterator from typing import TYPE_CHECKING import pytest -from httpx import AsyncClient, HTTPError from inline_snapshot import snapshot from mcp import ClientSession, StdioServerParameters, types -from mcp.client.sse import sse_client from mcp.client.stdio import stdio_client if TYPE_CHECKING: from mcp import ClientSession -CLI_JS_PATH = 'mcp-run-python/cli.js' +MAIN_TS = 'mcp-run-python/src/main.ts' pytestmark = pytest.mark.anyio +DENO_ARGS = [ + 'run', + '-N', + '-R=mcp-run-python/node_modules', + '-W=mcp-run-python/node_modules', + '--node-modules-dir=auto', + MAIN_TS, +] @pytest.fixture @@ -25,41 +28,43 @@ def anyio_backend(): return 'asyncio' -@pytest.fixture(name='mcp_session', params=['stdio', 'sse']) +# @pytest.fixture(name='mcp_session', params=['stdio', 'sse']) +@pytest.fixture(name='mcp_session', params=['stdio']) async def fixture_mcp_session(request: pytest.FixtureRequest) -> AsyncIterator[ClientSession]: if request.param == 'stdio': - server_params = StdioServerParameters(command='node', args=[CLI_JS_PATH, 'stdio']) + server_params = StdioServerParameters(command='deno', args=[*DENO_ARGS, 'stdio']) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: yield session else: - port = 3101 + raise NotImplementedError('SSE currently not working') + # port = 3101 - env = dict(os.environ) - env['PORT'] = str(port) - p = subprocess.Popen(['node', CLI_JS_PATH, 'sse'], env=env) - try: - url = f'http://localhost:{port}' - async with AsyncClient() as client: - for _ in range(5): - try: - await client.get(url, timeout=0.01) - except HTTPError: - await asyncio.sleep(0.1) - else: - break + # env = dict(os.environ) + # env['PORT'] = str(port) + # p = subprocess.Popen(['node', CLI_JS_PATH, 'sse'], env=env) + # try: + # url = f'http://localhost:{port}' + # async with AsyncClient() as client: + # for _ in range(5): + # try: + # await client.get(url, timeout=0.01) + # except HTTPError: + # await asyncio.sleep(0.1) + # else: + # break - async with sse_client(f'{url}/sse') as (read, write): - async with ClientSession(read, write) as session: - yield session - finally: - p.terminate() - exit_code = p.wait() - if exit_code > 0: - pytest.fail(f'Process exited with code {exit_code}') + # async with sse_client(f'{url}/sse') as (read, write): + # async with ClientSession(read, write) as session: + # yield session + # finally: + # p.terminate() + # exit_code = p.wait() + # if exit_code > 0: + # pytest.fail(f'Process exited with code {exit_code}') -async def test_stdio_list_tools(mcp_session: ClientSession) -> None: +async def test_list_tools(mcp_session: ClientSession) -> None: await mcp_session.initialize() tools = await mcp_session.list_tools() assert len(tools.tools) == 1 @@ -129,7 +134,7 @@ async def test_stdio_list_tools(mcp_session: ClientSession) -> None: ), ], ) -async def test_stdio_run_python_code(mcp_session: ClientSession, code: list[str], expected_output: str) -> None: +async def test_run_python_code(mcp_session: ClientSession, code: list[str], expected_output: str) -> None: await mcp_session.initialize() result = await mcp_session.call_tool('run_python_code', {'python_code': '\n'.join(code)}) assert len(result.content) == 1 From 55fafda51671bb81d2b53b3154d8877aa1ca5535 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 11:53:11 +0100 Subject: [PATCH 04/15] fix mcp-run-python ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a31e223be0..c101963653 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -237,7 +237,7 @@ jobs: deno-version: v2.x - run: | - deno run format + deno run fmt deno run lint deno run check working-directory: mcp-run-python From 600f308caedae1d7b8720b4cb7bdc11a5e858a78 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 12:41:56 +0100 Subject: [PATCH 05/15] fix mcp-run-python ci, take 2 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c101963653..f0a0bab832 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -237,9 +237,9 @@ jobs: deno-version: v2.x - run: | - deno run fmt - deno run lint - deno run check + deno fmt + deno lint + deno check src working-directory: mcp-run-python - run: uv run --package mcp-run-python pytest mcp-run-python -v From 76ff0c9b0397b90c1ca41514acdea5d67e272b10 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 12:49:18 +0100 Subject: [PATCH 06/15] fix warmup ci run --- .github/workflows/ci.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0a0bab832..5766e2398d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,13 +245,14 @@ jobs: - run: uv run --package mcp-run-python pytest mcp-run-python -v # check warmup works - - run: > - deno run - -N - -R=node_modules - -W=node_modules - --node-modules-dir=auto - src/main.ts + - name: warmup + run: | + deno run \ + -N \ + -R=node_modules \ + -W=node_modules \ + --node-modules-dir=auto \ + src/main.ts \ warmup working-directory: mcp-run-python From a9268393bad772b203da34ede1cc23e5cd5f0ef6 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 15:27:16 +0100 Subject: [PATCH 07/15] cleanup and formatting --- README.md | 99 ++++++++----- mcp-run-python/deno.json | 8 +- mcp-run-python/src/main.ts | 206 ++++++++++++++------------- mcp-run-python/src/prepareEnvCode.ts | 2 +- mcp-run-python/src/runCode.ts | 164 ++++++++++----------- 5 files changed, 258 insertions(+), 221 deletions(-) diff --git a/README.md b/README.md index 92c38bf25f..0f05b6df17 100644 --- a/README.md +++ b/README.md @@ -23,43 +23,65 @@ --- -PydanticAI is a Python agent framework designed to make it less painful to build production grade applications with Generative AI. +PydanticAI is a Python agent framework designed to make it less painful to build +production grade applications with Generative AI. -FastAPI revolutionized web development by offering an innovative and ergonomic design, built on the foundation of [Pydantic](https://docs.pydantic.dev). +FastAPI revolutionized web development by offering an innovative and ergonomic +design, built on the foundation of [Pydantic](https://docs.pydantic.dev). -Similarly, virtually every agent framework and LLM library in Python uses Pydantic, yet when we began to use LLMs in [Pydantic Logfire](https://pydantic.dev/logfire), we couldn't find anything that gave us the same feeling. +Similarly, virtually every agent framework and LLM library in Python uses +Pydantic, yet when we began to use LLMs in +[Pydantic Logfire](https://pydantic.dev/logfire), we couldn't find anything that +gave us the same feeling. -We built PydanticAI with one simple aim: to bring that FastAPI feeling to GenAI app development. +We built PydanticAI with one simple aim: to bring that FastAPI feeling to GenAI +app development. ## Why use PydanticAI -* __Built by the Pydantic Team__ -Built by the team behind [Pydantic](https://docs.pydantic.dev/latest/) (the validation layer of the OpenAI SDK, the Anthropic SDK, LangChain, LlamaIndex, AutoGPT, Transformers, CrewAI, Instructor and many more). - -* __Model-agnostic__ -Supports OpenAI, Anthropic, Gemini, Deepseek, Ollama, Groq, Cohere, and Mistral, and there is a simple interface to implement support for [other models](https://ai.pydantic.dev/models/). - -* __Pydantic Logfire Integration__ -Seamlessly [integrates](https://ai.pydantic.dev/logfire/) with [Pydantic Logfire](https://pydantic.dev/logfire) for real-time debugging, performance monitoring, and behavior tracking of your LLM-powered applications. - -* __Type-safe__ -Designed to make [type checking](https://ai.pydantic.dev/agents/#static-type-checking) as powerful and informative as possible for you. - -* __Python-centric Design__ -Leverages Python's familiar control flow and agent composition to build your AI-driven projects, making it easy to apply standard Python best practices you'd use in any other (non-AI) project. - -* __Structured Responses__ -Harnesses the power of [Pydantic](https://docs.pydantic.dev/latest/) to [validate and structure](https://ai.pydantic.dev/results/#structured-result-validation) model outputs, ensuring responses are consistent across runs. - -* __Dependency Injection System__ -Offers an optional [dependency injection](https://ai.pydantic.dev/dependencies/) system to provide data and services to your agent's [system prompts](https://ai.pydantic.dev/agents/#system-prompts), [tools](https://ai.pydantic.dev/tools/) and [result validators](https://ai.pydantic.dev/results/#result-validators-functions). -This is useful for testing and eval-driven iterative development. - -* __Streamed Responses__ -Provides the ability to [stream](https://ai.pydantic.dev/results/#streamed-results) LLM outputs continuously, with immediate validation, ensuring rapid and accurate results. - -* __Graph Support__ -[Pydantic Graph](https://ai.pydantic.dev/graph) provides a powerful way to define graphs using typing hints, this is useful in complex applications where standard control flow can degrade to spaghetti code. +- **Built by the Pydantic Team** Built by the team behind + [Pydantic](https://docs.pydantic.dev/latest/) (the validation layer of the + OpenAI SDK, the Anthropic SDK, LangChain, LlamaIndex, AutoGPT, Transformers, + CrewAI, Instructor and many more). + +- **Model-agnostic** Supports OpenAI, Anthropic, Gemini, Deepseek, Ollama, Groq, + Cohere, and Mistral, and there is a simple interface to implement support for + [other models](https://ai.pydantic.dev/models/). + +- **Pydantic Logfire Integration** Seamlessly + [integrates](https://ai.pydantic.dev/logfire/) with + [Pydantic Logfire](https://pydantic.dev/logfire) for real-time debugging, + performance monitoring, and behavior tracking of your LLM-powered + applications. + +- **Type-safe** Designed to make + [type checking](https://ai.pydantic.dev/agents/#static-type-checking) as + powerful and informative as possible for you. + +- **Python-centric Design** Leverages Python's familiar control flow and agent + composition to build your AI-driven projects, making it easy to apply standard + Python best practices you'd use in any other (non-AI) project. + +- **Structured Responses** Harnesses the power of + [Pydantic](https://docs.pydantic.dev/latest/) to + [validate and structure](https://ai.pydantic.dev/results/#structured-result-validation) + model outputs, ensuring responses are consistent across runs. + +- **Dependency Injection System** Offers an optional + [dependency injection](https://ai.pydantic.dev/dependencies/) system to + provide data and services to your agent's + [system prompts](https://ai.pydantic.dev/agents/#system-prompts), + [tools](https://ai.pydantic.dev/tools/) and + [result validators](https://ai.pydantic.dev/results/#result-validators-functions). + This is useful for testing and eval-driven iterative development. + +- **Streamed Responses** Provides the ability to + [stream](https://ai.pydantic.dev/results/#streamed-results) LLM outputs + continuously, with immediate validation, ensuring rapid and accurate results. + +- **Graph Support** [Pydantic Graph](https://ai.pydantic.dev/graph) provides a + powerful way to define graphs using typing hints, this is useful in complex + applications where standard control flow can degrade to spaghetti code. ## Hello World Example @@ -88,13 +110,15 @@ The first known use of "hello, world" was in a 1974 textbook about the C program _(This example is complete, it can be run "as is")_ -Not very interesting yet, but we can easily add "tools", dynamic system prompts, and structured responses to build more powerful agents. +Not very interesting yet, but we can easily add "tools", dynamic system prompts, +and structured responses to build more powerful agents. ## Tools & Dependency Injection Example Here is a concise example using PydanticAI to build a support agent for a bank: -**(Better documented example [in the docs](https://ai.pydantic.dev/#tools-dependency-injection-example))** +**(Better documented example +[in the docs](https://ai.pydantic.dev/#tools-dependency-injection-example))** ```python from dataclasses import dataclass @@ -186,8 +210,11 @@ async def main(): ## Next Steps -To try PydanticAI yourself, follow the instructions [in the examples](https://ai.pydantic.dev/examples/). +To try PydanticAI yourself, follow the instructions +[in the examples](https://ai.pydantic.dev/examples/). -Read the [docs](https://ai.pydantic.dev/agents/) to learn more about building applications with PydanticAI. +Read the [docs](https://ai.pydantic.dev/agents/) to learn more about building +applications with PydanticAI. -Read the [API Reference](https://ai.pydantic.dev/api/agent/) to understand PydanticAI's interface. +Read the [API Reference](https://ai.pydantic.dev/api/agent/) to understand +PydanticAI's interface. diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json index 0a30945dd8..2c4ca752ee 100644 --- a/mcp-run-python/deno.json +++ b/mcp-run-python/deno.json @@ -1,6 +1,6 @@ { "name": "@pydantic/mcp-run-python", - "version": "0.0.7", + "version": "0.0.8", "license": "MIT", "nodeModulesDir": "auto", "exports": { @@ -14,5 +14,11 @@ "@std/cli": "jsr:@std/cli@^1.0.15", "pyodide": "npm:pyodide@^0.27.4", "zod": "npm:zod@^3.24.2" + }, + "fmt": { + "lineWidth": 120, + "semiColons": false, + "singleQuote": true, + "include": ["src/"] } } diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index d8a1a66707..de333dec83 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -1,29 +1,28 @@ -import http from "node:http"; -import { parseArgs } from "@std/cli/parse-args"; -import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { - type LoggingLevel, - SetLevelRequestSchema, -} from "@modelcontextprotocol/sdk/types.js"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; - -import { asXml, runCode } from "./runCode.ts"; +import http from 'node:http' +import { parseArgs } from '@std/cli/parse-args' +import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js' +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' +import { type LoggingLevel, SetLevelRequestSchema } from '@modelcontextprotocol/sdk/types.js' +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' +import { z } from 'zod' + +import { asXml, runCode } from './runCode.ts' + +const VERSION = '0.0.8' export async function main() { - const { args } = Deno; - if (args.length === 1 && args[0] === "stdio") { - await runStdio(); - } else if (args.length >= 1 && args[0] === "sse") { + const { args } = Deno + if (args.length === 1 && args[0] === 'stdio') { + await runStdio() + } else if (args.length >= 1 && args[0] === 'sse') { const flags = parseArgs(Deno.args, { - string: ["port"], - default: { port: "3001" }, - }); - const port = parseInt(flags.port); - runSse(port); - } else if (args.length === 1 && args[0] === "warmup") { - await warmup(); + string: ['port'], + default: { port: '3001' }, + }) + const port = parseInt(flags.port) + runSse(port) + } else if (args.length === 1 && args[0] === 'warmup') { + await warmup() } else { console.error( `\ @@ -33,8 +32,8 @@ Usage: deno run -N -R=node_modules -W=node_modules --node-modules-dir=auto jsr:@ options: --port Port to run the SSE server on (default: 3001)`, - ); - Deno.exit(1); + ) + Deno.exit(1) } } @@ -44,20 +43,18 @@ options: function createServer(): McpServer { const server = new McpServer( { - name: "MCP Run Python", - version: "0.0.1", + name: 'MCP Run Python', + version: VERSION, }, { - instructions: - 'Call the "run_python_code" tool with the Python code to run.', + instructions: 'Call the "run_python_code" tool with the Python code to run.', capabilities: { logging: {}, }, }, - ); + ) - const toolDescription = - `Tool to execute Python code and return stdout, stderr, and return value. + const toolDescription = `Tool to execute Python code and return stdout, stderr, and return value. The code may be async, and the value on the last line will be returned as the return value. @@ -70,132 +67,139 @@ with a comment of the form: # dependencies = ['pydantic'] # /// print('python code here') -`; +` - let setLogLevel: LoggingLevel = "emergency"; + let setLogLevel: LoggingLevel = 'emergency' server.server.setRequestHandler(SetLevelRequestSchema, (request) => { - setLogLevel = request.params.level; - return {}; - }); + setLogLevel = request.params.level + return {} + }) server.tool( - "run_python_code", + 'run_python_code', toolDescription, - { python_code: z.string().describe("Python code to run") }, + { python_code: z.string().describe('Python code to run') }, async ({ python_code }: { python_code: string }) => { - const logPromises: Promise[] = []; + const logPromises: Promise[] = [] const result = await runCode([{ - name: "main.py", + name: 'main.py', content: python_code, active: true, }], (level, data) => { if (LogLevels.indexOf(level) >= LogLevels.indexOf(setLogLevel)) { - logPromises.push(server.server.sendLoggingMessage({ level, data })); + logPromises.push(server.server.sendLoggingMessage({ level, data })) } - }); - await Promise.all(logPromises); + }) + await Promise.all(logPromises) return { - content: [{ type: "text", text: asXml(result) }], - }; + content: [{ type: 'text', text: asXml(result) }], + } }, - ); - return server; + ) + return server } /* * Run the MCP server using the SSE transport, e.g. over HTTP. */ function runSse(port: number) { - const mcpServer = createServer(); - const transports: { [sessionId: string]: SSEServerTransport } = {}; + const mcpServer = createServer() + const transports: { [sessionId: string]: SSEServerTransport } = {} const server = http.createServer(async (req, res) => { const url = new URL( - req.url ?? "", - `http://${req.headers.host ?? "unknown"}`, - ); - console.log({ url, method: req.method }); - let pathMatch = false; - function match(methods: string[], path: string): boolean { + req.url ?? '', + `http://${req.headers.host ?? 'unknown'}`, + ) + let pathMatch = false + function match(method: string, path: string): boolean { if (url.pathname === path) { - pathMatch = true; - return methods.includes(req.method!); + pathMatch = true + return req.method === method } - return false; + return false } - - if (match(["GET", "POST"], "/sse")) { - const transport = new SSEServerTransport("/sse", res); - transports[transport.sessionId] = transport; - res.on("close", () => { - delete transports[transport.sessionId]; - }); - await mcpServer.connect(transport); - } else if (match(["POST"], "/messages")) { - const sessionId = url.searchParams.get("sessionId") ?? ""; - const transport = transports[sessionId]; + function textResponse(status: number, text: string) { + res.setHeader('Content-Type', 'text/plain') + res.statusCode = status + res.end(`${text}\n`) + } + console.log(`${req.method} ${url}`) + + if (match('GET', '/sse')) { + const transport = new SSEServerTransport('/messages', res) + transports[transport.sessionId] = transport + res.on('close', () => { + delete transports[transport.sessionId] + }) + await mcpServer.connect(transport) + } else if (match('POST', '/messages')) { + const sessionId = url.searchParams.get('sessionId') ?? '' + const transport = transports[sessionId] if (transport) { - await transport.handlePostMessage(req, res); + await transport.handlePostMessage(req, res) } else { - res.setHeader("Content-Type", "text/plain"); - res.statusCode = 400; - res.end(`No transport found for sessionId '${sessionId}'`); + textResponse(400, `No transport found for sessionId '${sessionId}'`) } + } else if (pathMatch) { + textResponse(405, 'Method not allowed') } else { - res.setHeader("Content-Type", "text/plain"); - res.statusCode = pathMatch ? 405 : 404; - res.end(pathMatch ? "Method not allowed\n" : "Page not found\n"); + textResponse(404, 'Page not found') } - }); + }) server.listen(port, () => { - console.log(`Running MCP server with SSE transport on port ${port}`); - }); + console.log( + `Running MCP Run Python version ${VERSION} with SSE transport on port ${port}`, + ) + }) } /* * Run the MCP server using the Stdio transport. */ async function runStdio() { - const mcpServer = createServer(); - const transport = new StdioServerTransport(); - await mcpServer.connect(transport); + const mcpServer = createServer() + const transport = new StdioServerTransport() + await mcpServer.connect(transport) } /* * Run pyodide to download packages which can otherwise interrupt the server */ async function warmup() { - console.error("Running warmup script..."); + console.error( + `Running warmup script for MCP Run Python version ${VERSION}...`, + ) const code = ` import numpy a = numpy.array([1, 2, 3]) print('numpy array:', a) a -`; +` const result = await runCode([{ - name: "warmup.py", + name: 'warmup.py', content: code, active: true, }], (level, data) => // use warn to avoid recursion since console.log is patched in runCode - console.error(`${level}: ${data}`)); - console.log("Tool return value:"); - console.log(asXml(result)); - console.log("\nwarmup successful 🎉"); + console.error(`${level}: ${data}`)) + console.log('Tool return value:') + console.log(asXml(result)) + console.log('\nwarmup successful 🎉') } // list of log levels to use for level comparison const LogLevels: LoggingLevel[] = [ - "debug", - "info", - "notice", - "warning", - "error", - "critical", - "alert", - "emergency", -]; - -await main(); + 'debug', + 'info', + 'notice', + 'warning', + 'error', + 'critical', + 'alert', + 'emergency', +] + +await main() diff --git a/mcp-run-python/src/prepareEnvCode.ts b/mcp-run-python/src/prepareEnvCode.ts index 8d71400127..215d3aaaee 100644 --- a/mcp-run-python/src/prepareEnvCode.ts +++ b/mcp-run-python/src/prepareEnvCode.ts @@ -199,4 +199,4 @@ def _find_imports_to_install(imports: list[str]) -> Iterable[str]: yield package_name elif '.' not in module: yield module -`; +` diff --git a/mcp-run-python/src/runCode.ts b/mcp-run-python/src/runCode.ts index acc2b06f3c..fdb1d7084e 100644 --- a/mcp-run-python/src/runCode.ts +++ b/mcp-run-python/src/runCode.ts @@ -1,12 +1,12 @@ /* eslint @typescript-eslint/no-explicit-any: off */ -import { loadPyodide } from "pyodide"; -import { preparePythonCode } from "./prepareEnvCode.ts"; -import type { LoggingLevel } from "@modelcontextprotocol/sdk/types.js"; +import { loadPyodide } from 'pyodide' +import { preparePythonCode } from './prepareEnvCode.ts' +import type { LoggingLevel } from '@modelcontextprotocol/sdk/types.js' export interface CodeFile { - name: string; - content: string; - active: boolean; + name: string + content: string + active: boolean } export async function runCode( @@ -14,158 +14,158 @@ export async function runCode( log: (level: LoggingLevel, data: string) => void, ): Promise { // remove once https://github.com/pyodide/pyodide/pull/5514 is released - const realConsoleLog = console.log; + const realConsoleLog = console.log // deno-lint-ignore no-explicit-any - console.log = (...args: any[]) => log("debug", args.join(" ")); + console.log = (...args: any[]) => log('debug', args.join(' ')) - const output: string[] = []; + const output: string[] = [] const pyodide = await loadPyodide({ stdout: (msg) => { - log("info", msg); - output.push(msg); + log('info', msg) + output.push(msg) }, stderr: (msg) => { - log("warning", msg); - output.push(msg); + log('warning', msg) + output.push(msg) }, - }); + }) // see https://github.com/pyodide/pyodide/discussions/5512 - const origLoadPackage = pyodide.loadPackage; + const origLoadPackage = pyodide.loadPackage pyodide.loadPackage = (pkgs, options) => origLoadPackage(pkgs, { // stop pyodide printing to stdout/stderr - messageCallback: (msg: string) => log("debug", `loadPackage: ${msg}`), + messageCallback: (msg: string) => log('debug', `loadPackage: ${msg}`), errorCallback: (msg: string) => { - log("error", `loadPackage: ${msg}`); - output.push(`install error: ${msg}`); + log('error', `loadPackage: ${msg}`) + output.push(`install error: ${msg}`) }, ...options, - }); + }) - await pyodide.loadPackage(["micropip", "pydantic"]); - const sys = pyodide.pyimport("sys"); + await pyodide.loadPackage(['micropip', 'pydantic']) + const sys = pyodide.pyimport('sys') - const dirPath = "/tmp/mcp_run_python"; - sys.path.append(dirPath); - const pathlib = pyodide.pyimport("pathlib"); - pathlib.Path(dirPath).mkdir(); - const moduleName = "_prepare_env"; + const dirPath = '/tmp/mcp_run_python' + sys.path.append(dirPath) + const pathlib = pyodide.pyimport('pathlib') + pathlib.Path(dirPath).mkdir() + const moduleName = '_prepare_env' - pathlib.Path(`${dirPath}/${moduleName}.py`).write_text(preparePythonCode); + pathlib.Path(`${dirPath}/${moduleName}.py`).write_text(preparePythonCode) - const preparePyEnv: PreparePyEnv = pyodide.pyimport(moduleName); + const preparePyEnv: PreparePyEnv = pyodide.pyimport(moduleName) - const prepareStatus = await preparePyEnv.prepare_env(pyodide.toPy(files)); + const prepareStatus = await preparePyEnv.prepare_env(pyodide.toPy(files)) - let runResult: RunSuccess | RunError; - if (prepareStatus.kind == "error") { + let runResult: RunSuccess | RunError + if (prepareStatus.kind == 'error') { runResult = { - status: "install-error", + status: 'install-error', output, error: prepareStatus.message, - }; + } } else { - const { dependencies } = prepareStatus; - const activeFile = files.find((f) => f.active)! || files[0]; + const { dependencies } = prepareStatus + const activeFile = files.find((f) => f.active)! || files[0] try { const rawValue = await pyodide.runPythonAsync(activeFile.content, { - globals: pyodide.toPy({ __name__: "__main__" }), + globals: pyodide.toPy({ __name__: '__main__' }), filename: activeFile.name, - }); + }) runResult = { - status: "success", + status: 'success', dependencies, output, returnValueJson: preparePyEnv.dump_json(rawValue), - }; + } } catch (err) { runResult = { - status: "run-error", + status: 'run-error', dependencies, output, error: formatError(err), - }; + } } } - sys.stdout.flush(); - sys.stderr.flush(); - console.log = realConsoleLog; - return runResult; + sys.stdout.flush() + sys.stderr.flush() + console.log = realConsoleLog + return runResult } interface RunSuccess { - status: "success"; + status: 'success' // we could record stdout and stderr separately, but I suspect simplicity is more important - output: string[]; - dependencies: string[]; - returnValueJson: string | null; + output: string[] + dependencies: string[] + returnValueJson: string | null } interface RunError { - status: "install-error" | "run-error"; - output: string[]; - dependencies?: string[]; - error: string; + status: 'install-error' | 'run-error' + output: string[] + dependencies?: string[] + error: string } export function asXml(runResult: RunSuccess | RunError): string { - const xml = [`${runResult.status}`]; + const xml = [`${runResult.status}`] if (runResult.dependencies?.length) { xml.push( `${JSON.stringify(runResult.dependencies)}`, - ); + ) } if (runResult.output.length) { - xml.push(""); - const escapeXml = escapeClosing("output"); - xml.push(...runResult.output.map(escapeXml)); - xml.push(""); + xml.push('') + const escapeXml = escapeClosing('output') + xml.push(...runResult.output.map(escapeXml)) + xml.push('') } - if (runResult.status == "success") { + if (runResult.status == 'success') { if (runResult.returnValueJson) { - xml.push(""); - xml.push(escapeClosing("return_value")(runResult.returnValueJson)); - xml.push(""); + xml.push('') + xml.push(escapeClosing('return_value')(runResult.returnValueJson)) + xml.push('') } } else { - xml.push(""); - xml.push(escapeClosing("error")(runResult.error)); - xml.push(""); + xml.push('') + xml.push(escapeClosing('error')(runResult.error)) + xml.push('') } - return xml.join("\n"); + return xml.join('\n') } function escapeClosing(closingTag: string): (str: string) => string { - const regex = new RegExp(`)?`, "gi"); + const regex = new RegExp(`)?`, 'gi') const onMatch = (match: string) => { - return match.replace(//g, ">"); - }; - return (str) => str.replace(regex, onMatch); + return match.replace(//g, '>') + } + return (str) => str.replace(regex, onMatch) } // deno-lint-ignore no-explicit-any function formatError(err: any): string { - let errStr = err.toString(); - errStr = errStr.replace(/^PythonError: +/, ""); + let errStr = err.toString() + errStr = errStr.replace(/^PythonError: +/, '') // remove frames from inside pyodide errStr = errStr.replace( / {2}File "\/lib\/python\d+\.zip\/_pyodide\/.*\n {4}.*\n(?: {4,}\^+\n)?/g, - "", - ); - return errStr; + '', + ) + return errStr } interface PrepareSuccess { - kind: "success"; - dependencies: string[]; + kind: 'success' + dependencies: string[] } interface PrepareError { - kind: "error"; - message: string; + kind: 'error' + message: string } interface PreparePyEnv { - prepare_env: (files: CodeFile[]) => Promise; + prepare_env: (files: CodeFile[]) => Promise // deno-lint-ignore no-explicit-any - dump_json: (value: any) => string | null; + dump_json: (value: any) => string | null } From 57842a8e9a4a553812fb42889040d1a1ed9c9d37 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 15:30:56 +0100 Subject: [PATCH 08/15] revert README changes --- README.md | 99 +++++++++++++++------------------------- mcp-run-python/README.md | 8 ++-- 2 files changed, 39 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 0f05b6df17..92c38bf25f 100644 --- a/README.md +++ b/README.md @@ -23,65 +23,43 @@ --- -PydanticAI is a Python agent framework designed to make it less painful to build -production grade applications with Generative AI. +PydanticAI is a Python agent framework designed to make it less painful to build production grade applications with Generative AI. -FastAPI revolutionized web development by offering an innovative and ergonomic -design, built on the foundation of [Pydantic](https://docs.pydantic.dev). +FastAPI revolutionized web development by offering an innovative and ergonomic design, built on the foundation of [Pydantic](https://docs.pydantic.dev). -Similarly, virtually every agent framework and LLM library in Python uses -Pydantic, yet when we began to use LLMs in -[Pydantic Logfire](https://pydantic.dev/logfire), we couldn't find anything that -gave us the same feeling. +Similarly, virtually every agent framework and LLM library in Python uses Pydantic, yet when we began to use LLMs in [Pydantic Logfire](https://pydantic.dev/logfire), we couldn't find anything that gave us the same feeling. -We built PydanticAI with one simple aim: to bring that FastAPI feeling to GenAI -app development. +We built PydanticAI with one simple aim: to bring that FastAPI feeling to GenAI app development. ## Why use PydanticAI -- **Built by the Pydantic Team** Built by the team behind - [Pydantic](https://docs.pydantic.dev/latest/) (the validation layer of the - OpenAI SDK, the Anthropic SDK, LangChain, LlamaIndex, AutoGPT, Transformers, - CrewAI, Instructor and many more). - -- **Model-agnostic** Supports OpenAI, Anthropic, Gemini, Deepseek, Ollama, Groq, - Cohere, and Mistral, and there is a simple interface to implement support for - [other models](https://ai.pydantic.dev/models/). - -- **Pydantic Logfire Integration** Seamlessly - [integrates](https://ai.pydantic.dev/logfire/) with - [Pydantic Logfire](https://pydantic.dev/logfire) for real-time debugging, - performance monitoring, and behavior tracking of your LLM-powered - applications. - -- **Type-safe** Designed to make - [type checking](https://ai.pydantic.dev/agents/#static-type-checking) as - powerful and informative as possible for you. - -- **Python-centric Design** Leverages Python's familiar control flow and agent - composition to build your AI-driven projects, making it easy to apply standard - Python best practices you'd use in any other (non-AI) project. - -- **Structured Responses** Harnesses the power of - [Pydantic](https://docs.pydantic.dev/latest/) to - [validate and structure](https://ai.pydantic.dev/results/#structured-result-validation) - model outputs, ensuring responses are consistent across runs. - -- **Dependency Injection System** Offers an optional - [dependency injection](https://ai.pydantic.dev/dependencies/) system to - provide data and services to your agent's - [system prompts](https://ai.pydantic.dev/agents/#system-prompts), - [tools](https://ai.pydantic.dev/tools/) and - [result validators](https://ai.pydantic.dev/results/#result-validators-functions). - This is useful for testing and eval-driven iterative development. - -- **Streamed Responses** Provides the ability to - [stream](https://ai.pydantic.dev/results/#streamed-results) LLM outputs - continuously, with immediate validation, ensuring rapid and accurate results. - -- **Graph Support** [Pydantic Graph](https://ai.pydantic.dev/graph) provides a - powerful way to define graphs using typing hints, this is useful in complex - applications where standard control flow can degrade to spaghetti code. +* __Built by the Pydantic Team__ +Built by the team behind [Pydantic](https://docs.pydantic.dev/latest/) (the validation layer of the OpenAI SDK, the Anthropic SDK, LangChain, LlamaIndex, AutoGPT, Transformers, CrewAI, Instructor and many more). + +* __Model-agnostic__ +Supports OpenAI, Anthropic, Gemini, Deepseek, Ollama, Groq, Cohere, and Mistral, and there is a simple interface to implement support for [other models](https://ai.pydantic.dev/models/). + +* __Pydantic Logfire Integration__ +Seamlessly [integrates](https://ai.pydantic.dev/logfire/) with [Pydantic Logfire](https://pydantic.dev/logfire) for real-time debugging, performance monitoring, and behavior tracking of your LLM-powered applications. + +* __Type-safe__ +Designed to make [type checking](https://ai.pydantic.dev/agents/#static-type-checking) as powerful and informative as possible for you. + +* __Python-centric Design__ +Leverages Python's familiar control flow and agent composition to build your AI-driven projects, making it easy to apply standard Python best practices you'd use in any other (non-AI) project. + +* __Structured Responses__ +Harnesses the power of [Pydantic](https://docs.pydantic.dev/latest/) to [validate and structure](https://ai.pydantic.dev/results/#structured-result-validation) model outputs, ensuring responses are consistent across runs. + +* __Dependency Injection System__ +Offers an optional [dependency injection](https://ai.pydantic.dev/dependencies/) system to provide data and services to your agent's [system prompts](https://ai.pydantic.dev/agents/#system-prompts), [tools](https://ai.pydantic.dev/tools/) and [result validators](https://ai.pydantic.dev/results/#result-validators-functions). +This is useful for testing and eval-driven iterative development. + +* __Streamed Responses__ +Provides the ability to [stream](https://ai.pydantic.dev/results/#streamed-results) LLM outputs continuously, with immediate validation, ensuring rapid and accurate results. + +* __Graph Support__ +[Pydantic Graph](https://ai.pydantic.dev/graph) provides a powerful way to define graphs using typing hints, this is useful in complex applications where standard control flow can degrade to spaghetti code. ## Hello World Example @@ -110,15 +88,13 @@ The first known use of "hello, world" was in a 1974 textbook about the C program _(This example is complete, it can be run "as is")_ -Not very interesting yet, but we can easily add "tools", dynamic system prompts, -and structured responses to build more powerful agents. +Not very interesting yet, but we can easily add "tools", dynamic system prompts, and structured responses to build more powerful agents. ## Tools & Dependency Injection Example Here is a concise example using PydanticAI to build a support agent for a bank: -**(Better documented example -[in the docs](https://ai.pydantic.dev/#tools-dependency-injection-example))** +**(Better documented example [in the docs](https://ai.pydantic.dev/#tools-dependency-injection-example))** ```python from dataclasses import dataclass @@ -210,11 +186,8 @@ async def main(): ## Next Steps -To try PydanticAI yourself, follow the instructions -[in the examples](https://ai.pydantic.dev/examples/). +To try PydanticAI yourself, follow the instructions [in the examples](https://ai.pydantic.dev/examples/). -Read the [docs](https://ai.pydantic.dev/agents/) to learn more about building -applications with PydanticAI. +Read the [docs](https://ai.pydantic.dev/agents/) to learn more about building applications with PydanticAI. -Read the [API Reference](https://ai.pydantic.dev/api/agent/) to understand -PydanticAI's interface. +Read the [API Reference](https://ai.pydantic.dev/api/agent/) to understand PydanticAI's interface. diff --git a/mcp-run-python/README.md b/mcp-run-python/README.md index c8b09b0c5f..6af1e9d61c 100644 --- a/mcp-run-python/README.md +++ b/mcp-run-python/README.md @@ -1,11 +1,9 @@ # MCP Run Python -[Model Context Protocol](https://modelcontextprotocol.io/) server to run Python -code in a sandbox. +[Model Context Protocol](https://modelcontextprotocol.io/) server to run Python code in a sandbox. -The code is executed using [pyodide](https://pyodide.org) in -[deno](https://deno.com/) and is therefore isolated from the rest of the -operating system. +The code is executed using [pyodide](https://pyodide.org) in [deno](https://deno.com/) and is therefore +isolated from the rest of the operating system. The server can be run with [deno](https://deno.com/) installed using: From 2fda851b5adf04f480f367fc390d12eb8353aac1 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 17:22:54 +0100 Subject: [PATCH 09/15] hack around env variables --- docs/mcp/client.md | 30 +++++++---- docs/mcp/run-python.md | 63 +++++++++++++++------- mcp-run-python/README.md | 41 ++++++++++++++ mcp-run-python/deno.json | 2 +- mcp-run-python/src/main.ts | 5 +- mcp-run-python/src/polyfill.ts | 8 +++ mcp-run-python/src/prepareEnvCode.ts | 2 +- mcp-run-python/test_mcp_servers.py | 80 +++++++++++++++++----------- 8 files changed, 167 insertions(+), 64 deletions(-) create mode 100644 mcp-run-python/src/polyfill.ts diff --git a/docs/mcp/client.md b/docs/mcp/client.md index 093cb39b50..846667a140 100644 --- a/docs/mcp/client.md +++ b/docs/mcp/client.md @@ -12,7 +12,7 @@ pip/uv-add "pydantic-ai-slim[mcp]" ``` !!! note - MCP integration requires Python 3.10 or higher. +MCP integration requires Python 3.10 or higher. ## Usage @@ -28,7 +28,7 @@ Examples of both are shown below; [mcp-run-python](run-python.md) is used as the [`MCPServerHTTP`][pydantic_ai.mcp.MCPServerHTTP] connects over HTTP using the [HTTP + Server Sent Events transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) to a server. !!! note - [`MCPServerHTTP`][pydantic_ai.mcp.MCPServerHTTP] requires an MCP server to be running and accepting HTTP connections before calling [`agent.run_mcp_servers()`][pydantic_ai.Agent.run_mcp_servers]. Running the server is not managed by PydanticAI. +[`MCPServerHTTP`][pydantic_ai.mcp.MCPServerHTTP] requires an MCP server to be running and accepting HTTP connections before calling [`agent.run_mcp_servers()`][pydantic_ai.Agent.run_mcp_servers]. Running the server is not managed by PydanticAI. The name "HTTP" is used since this implemented will be adapted in future to use the new [Streamable HTTP](https://github.com/modelcontextprotocol/specification/pull/206) currently in development. @@ -62,12 +62,12 @@ _(This example is complete, it can be run "as is" with Python 3.10+ — you'll n **What's happening here?** -* The model is receiving the prompt "how many days between 2000-01-01 and 2025-03-18?" -* The model decides "Oh, I've got this `run_python_code` tool, that will be a good way to answer this question", and writes some python code to calculate the answer. -* The model returns a tool call -* PydanticAI sends the tool call to the MCP server using the SSE transport -* The model is called again with the return value of running the code -* The model returns the final answer +- The model is receiving the prompt "how many days between 2000-01-01 and 2025-03-18?" +- The model decides "Oh, I've got this `run_python_code` tool, that will be a good way to answer this question", and writes some python code to calculate the answer. +- The model returns a tool call +- PydanticAI sends the tool call to the MCP server using the SSE transport +- The model is called again with the return value of running the code +- The model returns the final answer You can visualise this clearly, and even see the code that's run by adding three lines of code to instrument the example with [logfire](https://logfire.pydantic.dev/docs): @@ -87,14 +87,22 @@ Will display as follows: The other transport offered by MCP is the [stdio transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) where the server is run as a subprocess and communicates with the client over `stdin` and `stdout`. In this case, you'd use the [`MCPServerStdio`][pydantic_ai.mcp.MCPServerStdio] class. !!! note - When using [`MCPServerStdio`][pydantic_ai.mcp.MCPServerStdio] servers, the [`agent.run_mcp_servers()`][pydantic_ai.Agent.run_mcp_servers] context manager is responsible for starting and stopping the server. - +When using [`MCPServerStdio`][pydantic_ai.mcp.MCPServerStdio] servers, the [`agent.run_mcp_servers()`][pydantic_ai.Agent.run_mcp_servers] context manager is responsible for starting and stopping the server. ```python {title="mcp_stdio_client.py" py="3.10"} from pydantic_ai import Agent from pydantic_ai.mcp import MCPServerStdio -server = MCPServerStdio('npx', ['-y', '@pydantic/mcp-run-python', 'stdio']) +server = MCPServerStdio('deno', + args=[ + 'run', + '-N', + '-R=node_modules', + '-W=node_modules', + '--node-modules-dir=auto', + 'jsr:@pydantic/mcp-run-python', + 'stdio', + ]) agent = Agent('openai:gpt-4o', mcp_servers=[server]) diff --git a/docs/mcp/run-python.md b/docs/mcp/run-python.md index f5f5956034..e2bb6c3210 100644 --- a/docs/mcp/run-python.md +++ b/docs/mcp/run-python.md @@ -1,27 +1,43 @@ # MCP Run Python -The **MCP Run Python** package is an MCP server that allows agents to execute Python code in a secure, sandboxed environment. It uses [Pyodide](https://pyodide.org/) to run Python code in a JavaScript environment, isolating execution from the host system. +The **MCP Run Python** package is an MCP server that allows agents to execute Python code in a secure, sandboxed environment. It uses [Pyodide](https://pyodide.org/) to run Python code in a JavaScript environment with [deno](https://deno.com/), isolating execution from the host system. ## Features -* **Secure Execution**: Run Python code in a sandboxed WebAssembly environment -* **Package Management**: Automatically detects and installs required dependencies -* **Complete Results**: Captures standard output, standard error, and return values -* **Asynchronous Support**: Runs async code properly -* **Error Handling**: Provides detailed error reports for debugging +- **Secure Execution**: Run Python code in a sandboxed WebAssembly environment +- **Package Management**: Automatically detects and installs required dependencies +- **Complete Results**: Captures standard output, standard error, and return values +- **Asynchronous Support**: Runs async code properly +- **Error Handling**: Provides detailed error reports for debugging ## Installation -The MCP Run Python server is distributed as an [NPM package](https://www.npmjs.com/package/@pydantic/mcp-run-python) and can be run directly using [`npx`](https://docs.npmjs.com/cli/v8/commands/npx): +The MCP Run Python server is distributed as an [NPM package](https://jsr.io/@pydantic/mcp-run-python) and can be run directly using [`deno run`](https://deno.com/): ```bash -npx @pydantic/mcp-run-python [stdio|sse] +deno run \ + -N -R=node_modules -W=node_modules \ + --node-modules-dir=auto \ + jsr:@pydantic/mcp-run-python \ + [stdio|sse|warmup] ``` -Where: - -* `stdio`: Runs the server with [stdin/stdout transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) (for subprocess usage) -* `sse`: Runs the server with [HTTP Server-Sent Events transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) (for remote connections) +where: + +- `-N -R=node_modules -W=node_modules` (alias of + `--allow-net --allow-read=node_modules --allow-write=node_modules`) allows + network access and read+write access to `./node_modules`. These are required + so pyodide can download and cache the Python standard library and packages +- `--node-modules-dir=auto` tells deno to use a local `node_modules` directory +- `stdio` runs the server with the + [Stdio MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) + — suitable for running the process as a subprocess locally +- `sse` runs the server with the + [SSE MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) + — running the server as an HTTP server to connect locally or remotely +- `warmup` will run a minimal Python script to download and cache the Python + standard library. This is also useful to check the server is running + correctly. Usage of `@pydantic/mcp-run-python` with PydanticAI is described in the [client](client.md#mcp-stdio-server) documentation. @@ -39,12 +55,21 @@ a = numpy.array([1, 2, 3]) print(a) a """ +server_params = StdioServerParameters( + command='deno', + args=[ + 'run', + '-N', + '-R=node_modules', + '-W=node_modules', + '--node-modules-dir=auto', + 'jsr:@pydantic/mcp-run-python', + 'stdio', + ], +) async def main(): - server_params = StdioServerParameters( - command='npx', args=['-y', '@pydantic/mcp-run-python', 'stdio'] - ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() @@ -96,9 +121,12 @@ As introduced in PEP 723, explained [here](https://packaging.python.org/en/lates This allows use of dependencies that aren't imported in the code, and is more explicit. ```py {title="inline_script_metadata.py" py="3.10"} -from mcp import ClientSession, StdioServerParameters +from mcp import ClientSession from mcp.client.stdio import stdio_client +# using `server_params` from the above example. +from mcp_run_python import server_params + code = """\ # /// script # dependencies = ["pydantic", "email-validator"] @@ -113,9 +141,6 @@ print(Model(email='hello@pydantic.dev')) async def main(): - server_params = StdioServerParameters( - command='npx', args=['-y', '@pydantic/mcp-run-python', 'stdio'] - ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() diff --git a/mcp-run-python/README.md b/mcp-run-python/README.md index 6af1e9d61c..c38ddbd6a3 100644 --- a/mcp-run-python/README.md +++ b/mcp-run-python/README.md @@ -31,3 +31,44 @@ where: - `warmup` will run a minimal Python script to download and cache the Python standard library. This is also useful to check the server is running correctly. + +To use `mcp-run-python` with the Python MCP client over `stdio`, use: + +```python +from mcp import ClientSession, StdioServerParameters +from mcp.client.stdio import stdio_client + +code = """ +import numpy +a = numpy.array([1, 2, 3]) +print(a) +a +""" +server_params = StdioServerParameters( + command='npx', + args=[ + 'run', + '-N', + '-R=node_modules', + '-W=node_modules', + '--node-modules-dir=auto', + 'jsr:@pydantic/mcp-run-python', + 'stdio', + ], +) + +async def main(): + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + await session.initialize() + tools = await session.list_tools() + print(tools) + result = await session.call_tool('run_python_code', {'python_code': code}) + print(result) + +if __name__ == '__main__': + import asyncio + asyncio.run(main()) +``` + +Usage of `@pydantic/mcp-run-python` with PydanticAI is described in the [client documentation](https://ai.pydantic.dev/mcp/client#mcp-stdio-server). diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json index 2c4ca752ee..fabcef67c3 100644 --- a/mcp-run-python/deno.json +++ b/mcp-run-python/deno.json @@ -1,6 +1,6 @@ { "name": "@pydantic/mcp-run-python", - "version": "0.0.8", + "version": "0.0.9", "license": "MIT", "nodeModulesDir": "auto", "exports": { diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index de333dec83..de6d7ca17c 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -1,3 +1,4 @@ +import './polyfill.ts' import http from 'node:http' import { parseArgs } from '@std/cli/parse-args' import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js' @@ -8,7 +9,7 @@ import { z } from 'zod' import { asXml, runCode } from './runCode.ts' -const VERSION = '0.0.8' +const VERSION = '0.0.9' export async function main() { const { args } = Deno @@ -125,7 +126,7 @@ function runSse(port: number) { res.statusCode = status res.end(`${text}\n`) } - console.log(`${req.method} ${url}`) + // console.log(`${req.method} ${url}`) if (match('GET', '/sse')) { const transport = new SSEServerTransport('/messages', res) diff --git a/mcp-run-python/src/polyfill.ts b/mcp-run-python/src/polyfill.ts new file mode 100644 index 0000000000..51ed03fd3c --- /dev/null +++ b/mcp-run-python/src/polyfill.ts @@ -0,0 +1,8 @@ +import process from 'node:process' + +// Stub `process.env` and always return an empty object +Object.defineProperty(process, 'env', { + get() { + return {} + }, +}) diff --git a/mcp-run-python/src/prepareEnvCode.ts b/mcp-run-python/src/prepareEnvCode.ts index 215d3aaaee..9cedb56b08 100644 --- a/mcp-run-python/src/prepareEnvCode.ts +++ b/mcp-run-python/src/prepareEnvCode.ts @@ -162,7 +162,7 @@ def _read_pep723_metadata(code: str) -> dict[str, Any]: Copied from https://packaging.python.org/en/latest/specifications/inline-script-metadata/#reference-implementation """ name = 'script' - magic_comment_regex = r'(?m)^# /// (?P[a-zA-Z0-9-]+)$\s(?P(^#(| .*)$\s)+)^# ///$' + magic_comment_regex = r'(?m)^# /// (?P[a-zA-Z0-9-]+)$\\s(?P(^#(| .*)$\\s)+)^# ///$' matches = list(filter(lambda m: m.group('type') == name, re.finditer(magic_comment_regex, code))) if len(matches) > 1: raise ValueError(f'Multiple {name} blocks found') diff --git a/mcp-run-python/test_mcp_servers.py b/mcp-run-python/test_mcp_servers.py index dc74138701..a11a6d5ba6 100644 --- a/mcp-run-python/test_mcp_servers.py +++ b/mcp-run-python/test_mcp_servers.py @@ -1,17 +1,20 @@ from __future__ import annotations as _annotations +import asyncio +import subprocess from collections.abc import AsyncIterator from typing import TYPE_CHECKING import pytest +from httpx import AsyncClient, HTTPError from inline_snapshot import snapshot from mcp import ClientSession, StdioServerParameters, types +from mcp.client.sse import sse_client from mcp.client.stdio import stdio_client if TYPE_CHECKING: from mcp import ClientSession -MAIN_TS = 'mcp-run-python/src/main.ts' pytestmark = pytest.mark.anyio DENO_ARGS = [ 'run', @@ -19,7 +22,7 @@ '-R=mcp-run-python/node_modules', '-W=mcp-run-python/node_modules', '--node-modules-dir=auto', - MAIN_TS, + 'mcp-run-python/src/main.ts', ] @@ -28,8 +31,7 @@ def anyio_backend(): return 'asyncio' -# @pytest.fixture(name='mcp_session', params=['stdio', 'sse']) -@pytest.fixture(name='mcp_session', params=['stdio']) +@pytest.fixture(name='mcp_session', params=['stdio', 'sse']) async def fixture_mcp_session(request: pytest.FixtureRequest) -> AsyncIterator[ClientSession]: if request.param == 'stdio': server_params = StdioServerParameters(command='deno', args=[*DENO_ARGS, 'stdio']) @@ -37,31 +39,28 @@ async def fixture_mcp_session(request: pytest.FixtureRequest) -> AsyncIterator[C async with ClientSession(read, write) as session: yield session else: - raise NotImplementedError('SSE currently not working') - # port = 3101 + port = 3101 - # env = dict(os.environ) - # env['PORT'] = str(port) - # p = subprocess.Popen(['node', CLI_JS_PATH, 'sse'], env=env) - # try: - # url = f'http://localhost:{port}' - # async with AsyncClient() as client: - # for _ in range(5): - # try: - # await client.get(url, timeout=0.01) - # except HTTPError: - # await asyncio.sleep(0.1) - # else: - # break + p = subprocess.Popen(['deno', *DENO_ARGS, 'sse', f'--port={port}']) + try: + url = f'http://localhost:{port}' + async with AsyncClient() as client: + for _ in range(10): + try: + await client.get(url, timeout=0.01) + except HTTPError: + await asyncio.sleep(0.1) + else: + break - # async with sse_client(f'{url}/sse') as (read, write): - # async with ClientSession(read, write) as session: - # yield session - # finally: - # p.terminate() - # exit_code = p.wait() - # if exit_code > 0: - # pytest.fail(f'Process exited with code {exit_code}') + async with sse_client(f'{url}/sse') as (read, write): + async with ClientSession(read, write) as session: + yield session + finally: + p.terminate() + exit_code = p.wait() + if exit_code > 0: + pytest.fail(f'Process exited with code {exit_code}') async def test_list_tools(mcp_session: ClientSession) -> None: @@ -95,7 +94,7 @@ async def test_list_tools(mcp_session: ClientSession) -> None: 4 \ """), - id='basic_code', + id='basic-code', ), pytest.param( [ @@ -113,7 +112,28 @@ async def test_list_tools(mcp_session: ClientSession) -> None: ] \ """), - id='import_numpy', + id='import-numpy', + ), + pytest.param( + [ + '# /// script', + '# dependencies = ["pydantic", "email-validator"]', + '# ///', + 'import pydantic', + 'class Model(pydantic.BaseModel):', + ' email: pydantic.EmailStr', + "Model(email='hello@pydantic.dev')", + ], + snapshot("""\ +success +["pydantic","email-validator"] + +{ + "email": "hello@pydantic.dev" +} +\ +"""), + id='magic-comment-import', ), pytest.param( [ @@ -130,7 +150,7 @@ async def test_list_tools(mcp_session: ClientSession) -> None: \ """), - id='undefined_variable', + id='undefined-variable', ), ], ) From 5136b02063fb88fba8d3defcdbab501c8625e097 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 17:29:25 +0100 Subject: [PATCH 10/15] deploy mcp-run-server fix --- mcp-run-python/deno.json | 2 +- mcp-run-python/src/main.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json index fabcef67c3..15881b3fdc 100644 --- a/mcp-run-python/deno.json +++ b/mcp-run-python/deno.json @@ -1,6 +1,6 @@ { "name": "@pydantic/mcp-run-python", - "version": "0.0.9", + "version": "0.0.10", "license": "MIT", "nodeModulesDir": "auto", "exports": { diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index de6d7ca17c..22df30281a 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -9,7 +9,7 @@ import { z } from 'zod' import { asXml, runCode } from './runCode.ts' -const VERSION = '0.0.9' +const VERSION = '0.0.10' export async function main() { const { args } = Deno From b91eba3c3ef8c6bdf1022a644937ebe71f17c344 Mon Sep 17 00:00:00 2001 From: Petyo Ivanov Date: Wed, 2 Apr 2025 19:55:06 +0300 Subject: [PATCH 11/15] Fix errors in editor --- mcp-run-python/.gitignore | 1 + mcp-run-python/deno.json | 14 +++++++++++++- mcp-run-python/deno.lock | 10 ++++++++++ mcp-run-python/src/main.ts | 2 ++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 mcp-run-python/.gitignore diff --git a/mcp-run-python/.gitignore b/mcp-run-python/.gitignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/mcp-run-python/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json index 15881b3fdc..c61e97cb24 100644 --- a/mcp-run-python/deno.json +++ b/mcp-run-python/deno.json @@ -19,6 +19,18 @@ "lineWidth": 120, "semiColons": false, "singleQuote": true, - "include": ["src/"] + "include": [ + "src/" + ] + }, + "compilerOptions": { + "types": [ + "node" + ], + "lib": [ + "ESNext", + "deno.ns", + "dom" // console needs this + ] } } diff --git a/mcp-run-python/deno.lock b/mcp-run-python/deno.lock index 25c722fada..683d0fd9d6 100644 --- a/mcp-run-python/deno.lock +++ b/mcp-run-python/deno.lock @@ -4,6 +4,7 @@ "jsr:@std/cli@*": "1.0.15", "jsr:@std/cli@^1.0.15": "1.0.15", "npm:@modelcontextprotocol/sdk@^1.8.0": "1.8.0_express@5.1.0_zod@3.24.2", + "npm:@types/node@*": "22.12.0", "npm:eslint@*": "9.23.0", "npm:pyodide@~0.27.4": "0.27.4", "npm:zod@^3.24.2": "3.24.2" @@ -108,6 +109,12 @@ "@types/json-schema@7.0.15": { "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, + "@types/node@22.12.0": { + "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", + "dependencies": [ + "undici-types" + ] + }, "accepts@2.0.0": { "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dependencies": [ @@ -846,6 +853,9 @@ "mime-types" ] }, + "undici-types@6.20.0": { + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" + }, "unpipe@1.0.0": { "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index 22df30281a..ca6235c2ae 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -1,3 +1,5 @@ +/// + import './polyfill.ts' import http from 'node:http' import { parseArgs } from '@std/cli/parse-args' From 2d49bd81cbf89a032ad0f7e72f0010a4f766cba2 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 2 Apr 2025 18:23:50 +0100 Subject: [PATCH 12/15] add deno to tests in ci --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5766e2398d..1c85804888 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -143,6 +143,10 @@ jobs: with: enable-cache: true + - uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + - run: mkdir coverage # run tests with just `pydantic-ai-slim` dependencies From fe667f21ebf7cdb9d186e953c32befa121ef835f Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Thu, 3 Apr 2025 10:11:57 +0100 Subject: [PATCH 13/15] improve docs --- docs/mcp/client.md | 14 +++++--- docs/mcp/run-python.md | 18 +++++----- mcp-run-python/README.md | 51 +++++++++++++---------------- mcp-run-python/deno.json | 2 +- mcp-run-python/src/main.ts | 2 +- pydantic_ai_slim/pydantic_ai/mcp.py | 16 +++++++-- 6 files changed, 58 insertions(+), 45 deletions(-) diff --git a/docs/mcp/client.md b/docs/mcp/client.md index 846667a140..73efcf73c4 100644 --- a/docs/mcp/client.md +++ b/docs/mcp/client.md @@ -12,7 +12,7 @@ pip/uv-add "pydantic-ai-slim[mcp]" ``` !!! note -MCP integration requires Python 3.10 or higher. + MCP integration requires Python 3.10 or higher. ## Usage @@ -36,7 +36,9 @@ The name "HTTP" is used since this implemented will be adapted in future to use Before creating the SSE client, we need to run the server (docs [here](run-python.md)): ```bash {title="terminal (run sse server)"} -npx @pydantic/mcp-run-python sse +deno run \ + -N -R=node_modules -W=node_modules --node-modules-dir=auto \ + jsr:@pydantic/mcp-run-python sse ``` ```python {title="mcp_sse_client.py" py="3.10"} @@ -93,7 +95,8 @@ When using [`MCPServerStdio`][pydantic_ai.mcp.MCPServerStdio] servers, the [`age from pydantic_ai import Agent from pydantic_ai.mcp import MCPServerStdio -server = MCPServerStdio('deno', +server = MCPServerStdio( # (1)! + 'deno', args=[ 'run', '-N', @@ -102,7 +105,8 @@ server = MCPServerStdio('deno', '--node-modules-dir=auto', 'jsr:@pydantic/mcp-run-python', 'stdio', - ]) + ] +) agent = Agent('openai:gpt-4o', mcp_servers=[server]) @@ -112,3 +116,5 @@ async def main(): print(result.data) #> There are 9,208 days between January 1, 2000, and March 18, 2025. ``` + +1. See [MCP Run Python](run-python.md) for more information. diff --git a/docs/mcp/run-python.md b/docs/mcp/run-python.md index e2bb6c3210..6f235fbc2e 100644 --- a/docs/mcp/run-python.md +++ b/docs/mcp/run-python.md @@ -1,6 +1,6 @@ # MCP Run Python -The **MCP Run Python** package is an MCP server that allows agents to execute Python code in a secure, sandboxed environment. It uses [Pyodide](https://pyodide.org/) to run Python code in a JavaScript environment with [deno](https://deno.com/), isolating execution from the host system. +The **MCP Run Python** package is an MCP server that allows agents to execute Python code in a secure, sandboxed environment. It uses [Pyodide](https://pyodide.org/) to run Python code in a JavaScript environment with [Deno](https://deno.com/), isolating execution from the host system. ## Features @@ -12,14 +12,16 @@ The **MCP Run Python** package is an MCP server that allows agents to execute Py ## Installation -The MCP Run Python server is distributed as an [NPM package](https://jsr.io/@pydantic/mcp-run-python) and can be run directly using [`deno run`](https://deno.com/): +!!! warning "Switch from npx to deno" + We previously distributed `mcp-run-python` as an `npm` package to use via `npx`. + We now recommend using `deno` instead as it provides better sandboxing and security. + +The MCP Run Python server is distributed as a [JSR package](https://jsr.io/@pydantic/mcp-run-python) and can be run directly using [`deno run`](https://deno.com/): ```bash deno run \ - -N -R=node_modules -W=node_modules \ - --node-modules-dir=auto \ - jsr:@pydantic/mcp-run-python \ - [stdio|sse|warmup] + -N -R=node_modules -W=node_modules --node-modules-dir=auto \ + jsr:@pydantic/mcp-run-python [stdio|sse|warmup] ``` where: @@ -27,7 +29,7 @@ where: - `-N -R=node_modules -W=node_modules` (alias of `--allow-net --allow-read=node_modules --allow-write=node_modules`) allows network access and read+write access to `./node_modules`. These are required - so pyodide can download and cache the Python standard library and packages + so Pyodide can download and cache the Python standard library and packages - `--node-modules-dir=auto` tells deno to use a local `node_modules` directory - `stdio` runs the server with the [Stdio MCP transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) @@ -39,7 +41,7 @@ where: standard library. This is also useful to check the server is running correctly. -Usage of `@pydantic/mcp-run-python` with PydanticAI is described in the [client](client.md#mcp-stdio-server) documentation. +Usage of `jsr:@pydantic/mcp-run-python` with PydanticAI is described in the [client](client.md#mcp-stdio-server) documentation. ## Direct Usage diff --git a/mcp-run-python/README.md b/mcp-run-python/README.md index c38ddbd6a3..fede408a19 100644 --- a/mcp-run-python/README.md +++ b/mcp-run-python/README.md @@ -2,17 +2,17 @@ [Model Context Protocol](https://modelcontextprotocol.io/) server to run Python code in a sandbox. -The code is executed using [pyodide](https://pyodide.org) in [deno](https://deno.com/) and is therefore +The code is executed using [Pyodide](https://pyodide.org) in [Deno](https://deno.com/) and is therefore isolated from the rest of the operating system. -The server can be run with [deno](https://deno.com/) installed using: +**See for complete documentation.** + +The server can be run with `deno` installed using: ```bash deno run \ - -N -R=node_modules -W=node_modules \ - --node-modules-dir=auto \ - jsr:@pydantic/mcp-run-python \ - [stdio|sse|warmup] + -N -R=node_modules -W=node_modules --node-modules-dir=auto \ + jsr:@pydantic/mcp-run-python [stdio|sse|warmup] ``` where: @@ -32,20 +32,19 @@ where: standard library. This is also useful to check the server is running correctly. -To use `mcp-run-python` with the Python MCP client over `stdio`, use: +Here's an example of using `@pydantic/mcp-run-python` with PydanticAI: ```python -from mcp import ClientSession, StdioServerParameters -from mcp.client.stdio import stdio_client +from pydantic_ai import Agent +from pydantic_ai.mcp import MCPServerStdio + +import logfire + +logfire.configure() +logfire.instrument_mcp() +logfire.instrument_pydantic_ai() -code = """ -import numpy -a = numpy.array([1, 2, 3]) -print(a) -a -""" -server_params = StdioServerParameters( - command='npx', +server = MCPServerStdio('deno', args=[ 'run', '-N', @@ -54,21 +53,17 @@ server_params = StdioServerParameters( '--node-modules-dir=auto', 'jsr:@pydantic/mcp-run-python', 'stdio', - ], -) + ]) +agent = Agent('claude-3-5-haiku-latest', mcp_servers=[server]) + async def main(): - async with stdio_client(server_params) as (read, write): - async with ClientSession(read, write) as session: - await session.initialize() - tools = await session.list_tools() - print(tools) - result = await session.call_tool('run_python_code', {'python_code': code}) - print(result) + async with agent.run_mcp_servers(): + result = await agent.run('How many days between 2000-01-01 and 2025-03-18?') + print(result.data) + #> There are 9,208 days between January 1, 2000, and March 18, 2025.w if __name__ == '__main__': import asyncio asyncio.run(main()) ``` - -Usage of `@pydantic/mcp-run-python` with PydanticAI is described in the [client documentation](https://ai.pydantic.dev/mcp/client#mcp-stdio-server). diff --git a/mcp-run-python/deno.json b/mcp-run-python/deno.json index c61e97cb24..1c9f13d2bd 100644 --- a/mcp-run-python/deno.json +++ b/mcp-run-python/deno.json @@ -1,6 +1,6 @@ { "name": "@pydantic/mcp-run-python", - "version": "0.0.10", + "version": "0.0.11", "license": "MIT", "nodeModulesDir": "auto", "exports": { diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index ca6235c2ae..4815248429 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -11,7 +11,7 @@ import { z } from 'zod' import { asXml, runCode } from './runCode.ts' -const VERSION = '0.0.10' +const VERSION = '0.0.11' export async function main() { const { args } = Deno diff --git a/pydantic_ai_slim/pydantic_ai/mcp.py b/pydantic_ai_slim/pydantic_ai/mcp.py index 1b8dca75aa..93e6e018dd 100644 --- a/pydantic_ai_slim/pydantic_ai/mcp.py +++ b/pydantic_ai_slim/pydantic_ai/mcp.py @@ -114,7 +114,18 @@ class MCPServerStdio(MCPServer): from pydantic_ai import Agent from pydantic_ai.mcp import MCPServerStdio - server = MCPServerStdio('npx', ['-y', '@pydantic/mcp-run-python', 'stdio']) # (1)! + server = MCPServerStdio( # (1)! + 'deno', + args=[ + 'run', + '-N', + '-R=node_modules', + '-W=node_modules', + '--node-modules-dir=auto', + 'jsr:@pydantic/mcp-run-python', + 'stdio', + ] + ) agent = Agent('openai:gpt-4o', mcp_servers=[server]) async def main(): @@ -177,8 +188,7 @@ async def main(): ... ``` - 1. E.g. you might be connecting to a server run with `npx @pydantic/mcp-run-python sse`, - see [MCP Run Python](../mcp/run-python.md) for more information. + 1. E.g. you might be connecting to a server run with [`mcp-run-python`](../mcp/run-python.md). 2. This will connect to a server running on `localhost:3001`. """ From f4b556cb2a50d07623a3a461df0a3ef9cc4c53cd Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Thu, 3 Apr 2025 10:19:44 +0100 Subject: [PATCH 14/15] fix admonitions --- docs/mcp/client.md | 2 +- docs/mcp/run-python.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mcp/client.md b/docs/mcp/client.md index 73efcf73c4..b0c59d27ec 100644 --- a/docs/mcp/client.md +++ b/docs/mcp/client.md @@ -28,7 +28,7 @@ Examples of both are shown below; [mcp-run-python](run-python.md) is used as the [`MCPServerHTTP`][pydantic_ai.mcp.MCPServerHTTP] connects over HTTP using the [HTTP + Server Sent Events transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) to a server. !!! note -[`MCPServerHTTP`][pydantic_ai.mcp.MCPServerHTTP] requires an MCP server to be running and accepting HTTP connections before calling [`agent.run_mcp_servers()`][pydantic_ai.Agent.run_mcp_servers]. Running the server is not managed by PydanticAI. + [`MCPServerHTTP`][pydantic_ai.mcp.MCPServerHTTP] requires an MCP server to be running and accepting HTTP connections before calling [`agent.run_mcp_servers()`][pydantic_ai.Agent.run_mcp_servers]. Running the server is not managed by PydanticAI. The name "HTTP" is used since this implemented will be adapted in future to use the new [Streamable HTTP](https://github.com/modelcontextprotocol/specification/pull/206) currently in development. diff --git a/docs/mcp/run-python.md b/docs/mcp/run-python.md index 6f235fbc2e..fca2461fd4 100644 --- a/docs/mcp/run-python.md +++ b/docs/mcp/run-python.md @@ -18,7 +18,7 @@ The **MCP Run Python** package is an MCP server that allows agents to execute Py The MCP Run Python server is distributed as a [JSR package](https://jsr.io/@pydantic/mcp-run-python) and can be run directly using [`deno run`](https://deno.com/): -```bash +```bash {title="terminal"} deno run \ -N -R=node_modules -W=node_modules --node-modules-dir=auto \ jsr:@pydantic/mcp-run-python [stdio|sse|warmup] From 2c2268040eb5b83d45b927f9cefd9ba76eba180c Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Thu, 3 Apr 2025 10:33:43 +0100 Subject: [PATCH 15/15] fix node types magic comment --- mcp-run-python/deno.lock | 1 + mcp-run-python/src/main.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mcp-run-python/deno.lock b/mcp-run-python/deno.lock index 683d0fd9d6..19c41eeebf 100644 --- a/mcp-run-python/deno.lock +++ b/mcp-run-python/deno.lock @@ -5,6 +5,7 @@ "jsr:@std/cli@^1.0.15": "1.0.15", "npm:@modelcontextprotocol/sdk@^1.8.0": "1.8.0_express@5.1.0_zod@3.24.2", "npm:@types/node@*": "22.12.0", + "npm:@types/node@22.12.0": "22.12.0", "npm:eslint@*": "9.23.0", "npm:pyodide@~0.27.4": "0.27.4", "npm:zod@^3.24.2": "3.24.2" diff --git a/mcp-run-python/src/main.ts b/mcp-run-python/src/main.ts index 4815248429..034d36d89d 100644 --- a/mcp-run-python/src/main.ts +++ b/mcp-run-python/src/main.ts @@ -1,4 +1,4 @@ -/// +/// import './polyfill.ts' import http from 'node:http'