diff --git a/src/oci-javascript-mcp-server/.dockerignore b/src/oci-javascript-mcp-server/.dockerignore index 28cac498..8dc74c84 100644 --- a/src/oci-javascript-mcp-server/.dockerignore +++ b/src/oci-javascript-mcp-server/.dockerignore @@ -1,9 +1,10 @@ * -!package.json -!package-lock.json !buf.gen.yaml !proto/ !proto/runner.proto +!runner/ +!runner/package.json +!runner/package-lock.json !src/ !src/grpc.ts !src/protocol.ts diff --git a/src/oci-javascript-mcp-server/CHANGELOG.md b/src/oci-javascript-mcp-server/CHANGELOG.md index d1f7d37d..5abf5b5d 100644 --- a/src/oci-javascript-mcp-server/CHANGELOG.md +++ b/src/oci-javascript-mcp-server/CHANGELOG.md @@ -1,9 +1,13 @@ # Changelog -## Unreleased +## 0.2.0 ### Fixed +- Select OCI session-token authentication using SDK profile inheritance and + keep profile diagnostics off MCP stdout. +- Keep `isolated-vm` out of host runtime dependencies and install the runner's + dependencies from a separate manifest, pruning code generators from the image. - Preserve OCI status codes, service codes, operation details, and request IDs in uncaught `run_javascript` errors so callers can assess failures and retry decisions. diff --git a/src/oci-javascript-mcp-server/Containerfile b/src/oci-javascript-mcp-server/Containerfile index 296f7280..104a1977 100644 --- a/src/oci-javascript-mcp-server/Containerfile +++ b/src/oci-javascript-mcp-server/Containerfile @@ -10,33 +10,21 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends g++ make python3 \ && rm -rf /var/lib/apt/lists/* -COPY package.json package-lock.json ./ -RUN npm ci --include=dev \ - && npm cache clean --force +COPY runner/package.json runner/package-lock.json ./ +RUN npm ci --include=dev COPY buf.gen.yaml ./ COPY proto/ ./proto/ -RUN npx --no-install buf generate +RUN npx --no-install buf generate \ + && npm prune --omit=dev \ + && npm cache clean --force FROM node:26-bookworm-slim@sha256:cd565714d4da3e84bfd341e31448f81d47c6362198f152345297c9c1154e6341 WORKDIR /app COPY --from=dependencies --chown=65532:65532 \ - /app/node_modules/isolated-vm \ - ./node_modules/isolated-vm -COPY --from=dependencies --chown=65532:65532 \ - /app/node_modules/node-gyp-build \ - ./node_modules/node-gyp-build -COPY --from=dependencies --chown=65532:65532 \ - /app/node_modules/@grpc/grpc-js \ - ./node_modules/@grpc/grpc-js -COPY --from=dependencies --chown=65532:65532 \ - /app/node_modules/@js-sdsl/ordered-map \ - ./node_modules/@js-sdsl/ordered-map -COPY --from=dependencies --chown=65532:65532 \ - /app/node_modules/@bufbuild/protobuf \ - ./node_modules/@bufbuild/protobuf + /app/node_modules ./node_modules COPY --from=dependencies --chown=65532:65532 /app/src/generated/runner.ts ./src/generated/runner.ts COPY --chown=65532:65532 \ src/grpc.ts \ diff --git a/src/oci-javascript-mcp-server/README.md b/src/oci-javascript-mcp-server/README.md index 9737e15c..0cf66e3b 100644 --- a/src/oci-javascript-mcp-server/README.md +++ b/src/oci-javascript-mcp-server/README.md @@ -13,8 +13,10 @@ access, environment variables, or a network API. ## Quick start -Requires Node.js 26 or newer, rootless Podman, and an OCI SDK configuration. A -native build toolchain is also needed when installing `isolated-vm` on the host. +Requires Node.js 26 or newer, rootless Podman, and an OCI SDK configuration. +Production host installs omit `isolated-vm`; the container build installs it for +the runner. Building and testing from source also installs the addon and may +require a native build toolchain. From this directory: @@ -155,6 +157,23 @@ conservative mounts and network policy. ## Development +Run `npm ci --include=dev` to install test and development dependencies, including +`isolated-vm`. This requires a native build toolchain when no prebuilt addon is +available. The container build supplies its own build toolchain. + +The root manifest includes host runtime dependencies and development dependencies +for the combined host and runner tests. `runner/package.json` and its lockfile +define the container's runtime dependencies and development dependencies for +protobuf generation. The Containerfile installs both, generates the bindings, +and prunes development dependencies before copying modules into the final image. +Both runner build files are included in the published package so the image can +also be built from the package contents. + +When updating dependencies shared by the root and runner manifests, update both +declarations and regenerate both lockfiles. Keep the resolved versions aligned +so local tests exercise the same addon, gRPC libraries, and generators as the +container. + ```bash moon run oci-javascript-mcp-server:compile # generate bindings and compile the npm entry point moon run oci-javascript-mcp-server:test # unit and MCP stdio integration tests; 90% line minimum diff --git a/src/oci-javascript-mcp-server/moon.yml b/src/oci-javascript-mcp-server/moon.yml index 92a66fcf..a8724056 100644 --- a/src/oci-javascript-mcp-server/moon.yml +++ b/src/oci-javascript-mcp-server/moon.yml @@ -31,6 +31,7 @@ tasks: - 'test/**/*' - 'package.json' - 'package-lock.json' + - 'runner/*.json' check: description: 'Checks TypeScript types' @@ -61,6 +62,7 @@ tasks: - '.dockerignore' - 'package.json' - 'package-lock.json' + - 'runner/*.json' outputs: - 'dist/*.tgz' options: diff --git a/src/oci-javascript-mcp-server/package-lock.json b/src/oci-javascript-mcp-server/package-lock.json index d5f00170..835ccbad 100644 --- a/src/oci-javascript-mcp-server/package-lock.json +++ b/src/oci-javascript-mcp-server/package-lock.json @@ -1,18 +1,17 @@ { "name": "oci-javascript-mcp-server", - "version": "0.1.1", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "oci-javascript-mcp-server", - "version": "0.1.1", + "version": "0.2.0", "license": "UPL-1.0", "dependencies": { "@bufbuild/protobuf": "2.15.0", "@grpc/grpc-js": "^1.14.4", "@modelcontextprotocol/sdk": "^1.29.0", - "isolated-vm": "^7.0.0", "oci-common": "^2.132.0", "oci-sdk": "^2.132.0", "selfsigned": "^3.0.1", @@ -25,6 +24,7 @@ "@bufbuild/buf": "1.73.0", "@types/node": "^25.9.1", "c8": "^12.0.0", + "isolated-vm": "^7.0.0", "ts-proto": "2.12.4", "typescript": "^5.9.3" }, @@ -1531,6 +1531,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-7.0.0.tgz", "integrity": "sha512-TXlJp9kiSf4AEpkCgB4VIf2M+6MRW3SEzlZUXFmQ6QcRypOnENRvK6RoZuQt/dlLOnqyFGUoZELUfH4ucsG4iw==", + "dev": true, "hasInstallScript": true, "license": "ISC", "dependencies": { @@ -1914,6 +1915,7 @@ "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "dev": true, "license": "MIT", "bin": { "node-gyp-build": "bin.js", diff --git a/src/oci-javascript-mcp-server/package.json b/src/oci-javascript-mcp-server/package.json index 84eee8d0..aa655f5c 100644 --- a/src/oci-javascript-mcp-server/package.json +++ b/src/oci-javascript-mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "oci-javascript-mcp-server", - "version": "0.1.1", + "version": "0.2.0", "description": "Podman-isolated OCI JavaScript code execution MCP server", "type": "module", "keywords": [ @@ -25,6 +25,8 @@ "src/generated/runner.ts", "proto/", "buf.gen.yaml", + "runner/package.json", + "runner/package-lock.json", ".dockerignore", "Containerfile", "CHANGELOG.md", @@ -41,7 +43,6 @@ "@bufbuild/protobuf": "2.15.0", "@grpc/grpc-js": "^1.14.4", "@modelcontextprotocol/sdk": "^1.29.0", - "isolated-vm": "^7.0.0", "oci-common": "^2.132.0", "oci-sdk": "^2.132.0", "selfsigned": "^3.0.1", @@ -54,6 +55,7 @@ "@bufbuild/buf": "1.73.0", "@types/node": "^25.9.1", "c8": "^12.0.0", + "isolated-vm": "^7.0.0", "ts-proto": "2.12.4", "typescript": "^5.9.3" }, diff --git a/src/oci-javascript-mcp-server/runner/package-lock.json b/src/oci-javascript-mcp-server/runner/package-lock.json new file mode 100644 index 00000000..ad99df99 --- /dev/null +++ b/src/oci-javascript-mcp-server/runner/package-lock.json @@ -0,0 +1,596 @@ +{ + "name": "oci-javascript-mcp-runner", + "version": "0.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "oci-javascript-mcp-runner", + "version": "0.2.0", + "license": "UPL-1.0", + "dependencies": { + "@bufbuild/protobuf": "2.15.0", + "@grpc/grpc-js": "^1.14.4", + "isolated-vm": "^7.0.0" + }, + "devDependencies": { + "@bufbuild/buf": "1.73.0", + "ts-proto": "2.12.4" + }, + "engines": { + "node": ">=26" + } + }, + "node_modules/@bufbuild/buf": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.73.0.tgz", + "integrity": "sha512-W3whb4P1y3Hs9bqwCu9++W1v1ofHZ3dBUCe6JSZq0Ff5OK5UKKZuMN4iunPbgdyXY4+4ujEYf2ESrN/6MbcFSQ==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "bin": { + "buf": "bin/buf", + "protoc-gen-buf-breaking": "bin/protoc-gen-buf-breaking", + "protoc-gen-buf-lint": "bin/protoc-gen-buf-lint" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@bufbuild/buf-darwin-arm64": "1.73.0", + "@bufbuild/buf-darwin-x64": "1.73.0", + "@bufbuild/buf-linux-aarch64": "1.73.0", + "@bufbuild/buf-linux-armv7": "1.73.0", + "@bufbuild/buf-linux-x64": "1.73.0", + "@bufbuild/buf-win32-arm64": "1.73.0", + "@bufbuild/buf-win32-x64": "1.73.0" + } + }, + "node_modules/@bufbuild/buf-darwin-arm64": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.73.0.tgz", + "integrity": "sha512-cDd3y376ecClhyytNLlY3AtsZqsqXvEkQjMvrahrv/xUWWhEIX3efD8y0uufXDe8Yuk3sEmj7J1Xlx73Y46SkA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-darwin-x64": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.73.0.tgz", + "integrity": "sha512-VTBTCwaqT7otsMGXlk3MRu6x5hp+YH9PaLKcyWAa8wEt0NnMzbXdkE8GiLgI8Qkl7S3+pC9YSTCE/I+O87Fvrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-linux-aarch64": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.73.0.tgz", + "integrity": "sha512-HjoQ3wbLiUv5N5XLM3EAR2FY51Yn6t5MEXLPnS/Hx0KDkK/5eyIBZZ6toHBLjczAr1RTA1LagF38+lglZI+kvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-linux-armv7": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-armv7/-/buf-linux-armv7-1.73.0.tgz", + "integrity": "sha512-NsZuVg8hXfGcR96Is14ArKxZg6pdJb6kb63bx2g7q8Cjo+gRqZMBFKGvF/fnQMxTrRQAm6hzeF4a2vV4W3lszg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-linux-x64": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.73.0.tgz", + "integrity": "sha512-dMe6lBQrlHTU7DzqzaR7Udky7R78EDzzxtYZQdjkZun9jKdjGR4fLbPWEPyY4rLGVyk6UUnrtkf5qoIK2SC6qw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-win32-arm64": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.73.0.tgz", + "integrity": "sha512-UmubCflc8zJ48bVW0WeGeVTkNuumJP//wCWKUmeTXT1iNlEqkpaXy6y7o8YJKHGWLfX0/1UV3oay9ti0EyojMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-win32-x64": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.73.0.tgz", + "integrity": "sha512-/Buo10rXzqNLnFDh3BpzGdcrx6OalcU8o8gUyObCFZA5wKcUvBVNDhhpMmoB6YeiOPpPn47jHgW4bSSlypaaOQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.15.0.tgz", + "integrity": "sha512-DAheWUkVr/SJTWCc+lg9dhY0eN4SaWlf4+bG1KzHeXbnqt0AfB/NX0Z+VunGlM1ki1B4zVvye27MpKh/svySUA==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.4.tgz", + "integrity": "sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.1.tgz", + "integrity": "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@grpc/proto-loader/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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@grpc/proto-loader/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@grpc/proto-loader/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/@grpc/proto-loader/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@grpc/proto-loader/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@grpc/proto-loader/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "license": "BSD-3-Clause" + }, + "node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/case-anything": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", + "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "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==", + "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==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dprint-node": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", + "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isolated-vm": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-7.0.0.tgz", + "integrity": "sha512-TXlJp9kiSf4AEpkCgB4VIf2M+6MRW3SEzlZUXFmQ6QcRypOnENRvK6RoZuQt/dlLOnqyFGUoZELUfH4ucsG4iw==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">=26.0.0" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/protobufjs": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", + "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ts-poet": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz", + "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dprint-node": "^1.0.8" + } + }, + "node_modules/ts-proto": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.12.4.tgz", + "integrity": "sha512-nZ2UyT+xEanL90lCnL0BrTfKtljZE4wnOvUqR0XUpuWCu3w4k8LUnR4AKJoy1UtxPDa1HpJ1z//pu2tvIPDrUA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.14.1", + "case-anything": "^2.1.13", + "ts-poet": "^6.12.0", + "ts-proto-descriptors": "2.1.0" + }, + "bin": { + "protoc-gen-ts_proto": "protoc-gen-ts_proto" + } + }, + "node_modules/ts-proto-descriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.1.0.tgz", + "integrity": "sha512-S5EZYEQ6L9KLFfjSRpZWDIXDV/W7tAj8uW7pLsihIxyr62EAVSiKuVPwE8iWnr849Bqa53enex1jhDUcpgquzA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/src/oci-javascript-mcp-server/runner/package.json b/src/oci-javascript-mcp-server/runner/package.json new file mode 100644 index 00000000..6fcac6c1 --- /dev/null +++ b/src/oci-javascript-mcp-server/runner/package.json @@ -0,0 +1,20 @@ +{ + "name": "oci-javascript-mcp-runner", + "version": "0.2.0", + "private": true, + "description": "Runtime and build dependencies for the OCI JavaScript sandbox container", + "type": "module", + "dependencies": { + "@bufbuild/protobuf": "2.15.0", + "@grpc/grpc-js": "^1.14.4", + "isolated-vm": "^7.0.0" + }, + "engines": { + "node": ">=26" + }, + "license": "UPL-1.0", + "devDependencies": { + "@bufbuild/buf": "1.73.0", + "ts-proto": "2.12.4" + } +} diff --git a/src/oci-javascript-mcp-server/src/oci-host.ts b/src/oci-javascript-mcp-server/src/oci-host.ts index e3271ea8..f3bc6018 100644 --- a/src/oci-javascript-mcp-server/src/oci-host.ts +++ b/src/oci-javascript-mcp-server/src/oci-host.ts @@ -579,51 +579,25 @@ function authenticationProvider(loadSdk: OciSdkLoader): any { const configFile = process.env.OCI_CONFIG_FILE ? resolve(process.env.OCI_CONFIG_FILE) : join(homedir(), ".oci", "config"); - const profile = process.env.OCI_CONFIG_PROFILE ?? "DEFAULT"; - const profileConfig = readProfile(configFile, profile); - - if (profileConfig.security_token_file && typeof common.SessionAuthDetailProvider === "function") { - return new common.SessionAuthDetailProvider(configFile, profile); - } - - const Provider = sdk.ConfigFileAuthenticationDetailsProvider - ?? common.ConfigFileAuthenticationDetailsProvider; - if (typeof Provider !== "function") { - throw new PublicError("OCI JavaScript SDK authentication provider is unavailable"); - } - return new Provider(configFile, profile); -} - -function readProfile(configFile: string, profile: string): Record { - if (!existsSync(configFile)) { - return {}; - } - const wanted = profile.toUpperCase(); - const result: Record = {}; - let active = false; - - for (const rawLine of readFileSync(configFile, "utf8").split(/\r?\n/)) { - const line = rawLine.trim(); - if (!line || line.startsWith("#") || line.startsWith(";")) { - continue; - } - const section = line.match(/^\[(.+)]$/); - if (section) { - active = section[1].toUpperCase() === wanted; - continue; - } - if (!active) { - continue; + const profile = process.env.OCI_CONFIG_PROFILE || "DEFAULT"; + // The SDK logs missing DEFAULT profiles to stdout. Both operations are synchronous. + const info = console.info; + console.info = console.error; + try { + const profileConfig = common.ConfigFileReader.parseFileFromPath(configFile, profile); + if (profileConfig.get("security_token_file") && typeof common.SessionAuthDetailProvider === "function") { + return new common.SessionAuthDetailProvider(configFile, profile); } - const equalsIndex = line.indexOf("="); - if (equalsIndex === -1) { - continue; + + const Provider = sdk.ConfigFileAuthenticationDetailsProvider + ?? common.ConfigFileAuthenticationDetailsProvider; + if (typeof Provider !== "function") { + throw new PublicError("OCI JavaScript SDK authentication provider is unavailable"); } - const key = line.slice(0, equalsIndex).trim(); - const value = line.slice(equalsIndex + 1).trim(); - result[key] = value; + return new Provider(configFile, profile); + } finally { + console.info = info; } - return result; } function decodeRequest(request: JsonObject): Record { diff --git a/src/oci-javascript-mcp-server/src/server.ts b/src/oci-javascript-mcp-server/src/server.ts index a1ad1f41..20f37cdf 100755 --- a/src/oci-javascript-mcp-server/src/server.ts +++ b/src/oci-javascript-mcp-server/src/server.ts @@ -34,7 +34,7 @@ let activeToolCalls = 0; const server = new McpServer({ name: "oci-javascript-mcp-server", - version: "0.1.1" + version: "0.2.0" }, { instructions: ( "Run one complete JavaScript script against the injected OCI binding. " diff --git a/src/oci-javascript-mcp-server/test/oci-host.test.ts b/src/oci-javascript-mcp-server/test/oci-host.test.ts index deb1725f..45004842 100644 --- a/src/oci-javascript-mcp-server/test/oci-host.test.ts +++ b/src/oci-javascript-mcp-server/test/oci-host.test.ts @@ -15,6 +15,52 @@ import { createOciReflectionManifest, createOciSdkHostRpc } from "../src/oci-hos const require = createRequire(import.meta.url); const common = require("oci-common") as Record; +const { ConfigFileReader } = common; + +// Even mocked providers use the real SDK profile reader, never the developer's config. +const configDirectory = mkdtempSync(join(tmpdir(), "oci-host-config-")); +const previousConfig = { + OCI_CONFIG_FILE: process.env.OCI_CONFIG_FILE, + OCI_CONFIG_PROFILE: process.env.OCI_CONFIG_PROFILE +}; +test.beforeEach(() => { + process.env.OCI_CONFIG_FILE = join(configDirectory, "config"); + process.env.OCI_CONFIG_PROFILE = "DEFAULT"; + writeFileSync(process.env.OCI_CONFIG_FILE, "[DEFAULT]\n"); +}); +test.after(() => { + for (const [key, value] of Object.entries(previousConfig)) { + if (value === undefined) delete process.env[key]; + else process.env[key] = value; + } + rmSync(configDirectory, { recursive: true, force: true }); +}); + +for (const fail of [false, true]) { + test(`host redirects SDK diagnostics and restores logging after ${fail ? "failure" : "success"}`, async t => { + const info = t.mock.method(console, "info", () => {}); + const stderr = t.mock.method(console, "error", () => {}); + writeFileSync(process.env.OCI_CONFIG_FILE!, "[WORK]\n"); + process.env.OCI_CONFIG_PROFILE = "WORK"; + class Provider { + constructor(path: string, profile: string) { + // Real providers parse the file again during construction. + ConfigFileReader.parseFileFromPath(path, profile); + if (fail) throw new Error("authentication failed"); + } + } + const hostRpc = createOciSdkHostRpc(() => ({ + sdk: { ConfigFileAuthenticationDetailsProvider: Provider }, + common: { ConfigFileReader } + })); + const result = hostRpc({ binding: "oracle", namespace: "oci", operation: "config", payload: {} }); + if (fail) await assert.rejects(result, /authentication failed/); + else await assert.doesNotReject(result); + assert.equal(info.mock.callCount(), 0, "SDK diagnostics must not reach stdout"); + assert(stderr.mock.callCount() > 0); + assert.equal(console.info, info, "logging must be restored after construction"); + }); +} test("host RPC config returns principal from config-file user", async () => { class Provider { @@ -42,7 +88,7 @@ test("host RPC config returns principal from config-file user", async () => { sdk: { ConfigFileAuthenticationDetailsProvider: Provider }, - common: {} + common: { ConfigFileReader } })); return hostRpc({ binding: "oracle", @@ -73,7 +119,7 @@ test("host RPC config preserves null and omitted metadata fields", async () => { } const result = await withTemporaryOciConfig("[DEFAULT]\n", async () => { const hostRpc = createOciSdkHostRpc(() => ({ - sdk: { ConfigFileAuthenticationDetailsProvider: Provider }, common: {} + sdk: { ConfigFileAuthenticationDetailsProvider: Provider }, common: { ConfigFileReader } })); return hostRpc({ binding: "oracle", namespace: "oci", operation: "config", payload: {} }); }); @@ -84,7 +130,7 @@ test("host RPC config preserves null and omitted metadata fields", async () => { } }); -test("host RPC config derives only principal id from session token", async () => { +test("host RPC config derives only principal id from an inherited session token", async () => { const token = fakeJwt({ sub: "ocid1.user.oc1..sessionuser", email: "user@example.com", @@ -118,12 +164,15 @@ test("host RPC config derives only principal id from session token", async () => "[DEFAULT]", "tenancy=ocid1.tenancy.oc1..example", "region=us-ashburn-1", - "security_token_file=/not/read/by/mock" + "security_token_file=/not/read/by/mock", + "[WORK]" ].join("\n"), async () => { + process.env.OCI_CONFIG_PROFILE = "WORK"; const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: { + ConfigFileReader, SessionAuthDetailProvider: SessionProvider } })); @@ -173,7 +222,7 @@ test("host RPC invokes OCI JavaScript SDK clients", async () => { ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); const result = await hostRpc({ @@ -197,7 +246,7 @@ test("host RPC invokes OCI JavaScript SDK clients", async () => { }); assert.equal( (calls[0] as { constructor: { additionalUserAgent?: string } }).constructor.additionalUserAgent, - "oci-javascript-mcp/0.1.1" + "oci-javascript-mcp/0.2.0" ); assert.deepEqual(calls[1], { listInstances: { @@ -231,7 +280,7 @@ test("host RPC applies per-client region to a fresh provider", async () => { ConfigFileAuthenticationDetailsProvider: Provider, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); await hostRpc({ @@ -275,7 +324,7 @@ test("host RPC applies the trusted cancellation signal to OCI clients", async () ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); const abortController = new AbortController(); await hostRpc({ @@ -405,7 +454,7 @@ test("host cancellation and retry policy work with real OCI SDK clients", async }); test("host RPC rejects unsupported client options", async () => { - const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: {} })); + const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: { ConfigFileReader } })); await assert.rejects( hostRpc({ @@ -427,7 +476,7 @@ test("host RPC rejects unsupported client options", async () => { }); test("host RPC rejects malformed client regions", async () => { - const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: {} })); + const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: { ConfigFileReader } })); await assert.rejects( hostRpc({ @@ -468,7 +517,7 @@ test("host RPC preserves fields returned by SDK operations", async () => { ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); const result = await hostRpc({ @@ -512,7 +561,7 @@ test("host RPC rejects SDK helper methods before invocation", async () => { ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); await assert.rejects( @@ -547,7 +596,7 @@ test("host RPC points SDK pagination helpers to direct list page tokens", async ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); await assert.rejects( @@ -612,7 +661,7 @@ function base64UrlJson(value: Record): string { } test("host RPC rejects invalid identifiers before SDK lookup", async () => { - const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: {} })); + const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: { ConfigFileReader } })); await assert.rejects( hostRpc({ @@ -642,7 +691,7 @@ test("host RPC discovers services and clients", async () => { core: { ComputeClient, VirtualNetworkClient }, identity: {} }, - common: {} + common: { ConfigFileReader } })); assert.deepEqual( @@ -737,7 +786,7 @@ test("host builds reflection manifest from installed SDK shape", () => { core: { ComputeClient, VirtualNetworkClient }, identity: {} }, - common: {} + common: { ConfigFileReader } })); assert.deepEqual(manifest, { @@ -760,7 +809,7 @@ test("host builds reflection manifest from installed SDK shape", () => { }); test("host RPC rejects unsupported envelopes", async () => { - const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: {} })); + const hostRpc = createOciSdkHostRpc(() => ({ sdk: {}, common: { ConfigFileReader } })); await assert.rejects( hostRpc({ binding: "other" as never, @@ -784,7 +833,7 @@ test("host RPC rejects unsupported envelopes", async () => { test("host RPC reports unknown invoke targets", async () => { const hostRpc = createOciSdkHostRpc(() => ({ sdk: { core: {} }, - common: {} + common: { ConfigFileReader } })); await assert.rejects( hostRpc({ @@ -822,7 +871,7 @@ test("host RPC reports unknown discovery targets and client operations", async ( } const hostRpc = createOciSdkHostRpc(() => ({ sdk: { core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); await assert.rejects( @@ -894,7 +943,7 @@ test("host RPC rejects oversized OCI responses", async () => { ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); await assert.rejects( @@ -926,7 +975,7 @@ test("host RPC rejects OCI responses that exceed structural and framing budgets" ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } }); const hostRpc = createOciSdkHostRpc(loadSdk); @@ -984,7 +1033,7 @@ test("host RPC handles an SDK operation disappearing from a client instance", as ConfigFileAuthenticationDetailsProvider: class Provider {}, core: { ComputeClient } }, - common: {} + common: { ConfigFileReader } })); await assert.rejects( diff --git a/src/oci-javascript-mcp-server/test/packaging.test.ts b/src/oci-javascript-mcp-server/test/packaging.test.ts index 498d546a..c9984b74 100644 --- a/src/oci-javascript-mcp-server/test/packaging.test.ts +++ b/src/oci-javascript-mcp-server/test/packaging.test.ts @@ -28,7 +28,8 @@ test("npm package runs from node_modules with compiled bindings", { timeout: 30_ for (const path of [ "dist/server.js", "dist/generated/runner.js", "dist/isolation/grpc-execution.js", "src/generated/runner.ts", "src/grpc.ts", "proto/runner.proto", - "buf.gen.yaml", "Containerfile", ".dockerignore" + "buf.gen.yaml", "Containerfile", ".dockerignore", + "runner/package.json", "runner/package-lock.json" ]) { assert.ok(files.has(path), `package is missing ${path}`); }