Two executors share an in-memory adapter and blob store, modeling a multi-tenant cloud topology: user A signs in and installs a shared MCP source at the org scope; user B (scope stack [userB, org]) has no connection or per-user secret. Run a real HTTP MCP server that records the Authorization header on every request so "leaked a token" becomes a direct assertion against the captured header. Covers both auth kinds the plugin supports for remote sources: * oauth2 — auth points at a Connection id that only resolves through user A's scope stack. * header — auth points at a per-user SecretId only planted in user A's scope. User A's invocation asserts the server actually saw user A's bearer on the wire (so the negative path can't pass by accident). User B's invocation must surface as ToolInvocationError wrapping an McpConnectionError, and no server request after that point may carry user A's token. Induced-regression check: replacing the `accessToken(...)` failure with `Effect.orElseSucceed(() => "")` makes user B's invoke succeed; the new test flips to Left→Right and fails as expected. Reverted after verification. No code fix — the SDK-level flow is correct. `resolveConnectorInput` maps `ConnectionNotFoundError` and `secrets.get(...) === null` into McpConnectionError, and `findInnermostConnectionRow` only walks the caller's scope stack, so user A's row at userA scope is invisible to user B's [userB, org] stack. Adds @executor/storage-core to the MCP plugin's devDependencies so the test can use `makeMemoryAdapter` directly for the shared-adapter harness.
Unified · Split
| @@ -624,6 +624,7 @@ · 623 unmodified lines | |||
| 624 | "@effect/vitest": "catalog:", | 624 | "@effect/vitest": "catalog:", |
| 625 | "@executor/api": "workspace:*", | 625 | "@executor/api": "workspace:*", |
| 626 | "@executor/react": "workspace:*", | 626 | "@executor/react": "workspace:*", |
| 627 | "@executor/storage-core": "workspace:*", | ||
| 627 | "@types/node": "catalog:", | 628 | "@types/node": "catalog:", |
| 628 | "@types/react": "catalog:", | 629 | "@types/react": "catalog:", |
| 629 | "bun-types": "catalog:", | 630 | "bun-types": "catalog:", |
| @@ -60,6 +60,7 @@ · 59 unmodified lines | |||
| 60 | "@effect/vitest": "catalog:", | 60 | "@effect/vitest": "catalog:", |
| 61 | "@executor/api": "workspace:*", | 61 | "@executor/api": "workspace:*", |
| 62 | "@executor/react": "workspace:*", | 62 | "@executor/react": "workspace:*", |
| 63 | "@executor/storage-core": "workspace:*", | ||
| 63 | "@types/node": "catalog:", | 64 | "@types/node": "catalog:", |
| 64 | "@types/react": "catalog:", | 65 | "@types/react": "catalog:", |
| 65 | "bun-types": "catalog:", | 66 | "bun-types": "catalog:", |
Binary file not shown.