{"_id":"@apollo/mcp-impostor-host","_rev":"4-68629b2d832b7fd94342eb0113bc1b7a","name":"@apollo/mcp-impostor-host","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@apollo/mcp-impostor-host","version":"0.1.0","license":"MIT","_id":"@apollo/mcp-impostor-host@0.1.0","maintainers":[{"name":"phryneas","email":"mail@lenzw.de"},{"name":"jerelmiller","email":"jerelmiller@gmail.com"}],"bin":{"serve-impostor-host":"bin/serve-impostor-host.js"},"dist":{"shasum":"d379fe925820cddbeb56c38faf9c1b6b2025a4a1","tarball":"https://registry.npmjs.org/@apollo/mcp-impostor-host/-/mcp-impostor-host-0.1.0.tgz","fileCount":62,"integrity":"sha512-rqzEB/Q3L+l0bf4DqW6d+6Hx3Ov5/UlFivezHgf5UPM6DgTppA3582gfMxIdI215HsFULXt2vKD+YbIF+4tMYA==","signatures":[{"sig":"MEYCIQCNXeYbcj6ysl17UOzGMaVjWqETNSGq49Po+cQtMd8c8QIhAL5cLmnbTun9UOnSrOKOPXhPt03KrAp8Wugg6XjeW+Y4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":920859},"main":"dist/core/index.js","type":"module","types":"dist/core/index.d.ts","module":"dist/core/index.js","exports":{".":{"types":"./dist/core/index.d.ts","default":"./dist/core/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./playwright":{"types":"./dist/playwright/index.d.ts","default":"./dist/playwright/index.js"}},"gitHead":"e9d9316de4b8d7f4c4584234f53b88cb1899c3c3","imports":{"#package.json":"./package.json"},"scripts":{"attw":"npm run build && attw --pack . --ignore-rules cjs-resolves-to-esm --profile node16","lint":"eslint .","test":"playwright test","build":"npm-run-all build:*","clean":"rimraf dist","format":"prettier --write .","prebuild":"npm run clean","build:lib":"tsc --build tsconfig.build.json","typecheck":"tsc --build tsconfig.json","format:check":"prettier --check .","build:harness":"vite build --mode harness","build:sandbox":"vite build --mode sandbox","changeset-publish":"npm run build && changeset publish"},"_npmUser":{"name":"jerelmiller","email":"jerelmiller@gmail.com"},"_npmVersion":"11.11.0","description":"A test host for MCP Apps — impersonates a real MCP Apps host (e.g. Claude Desktop) for end-to-end testing","directories":{},"_nodeVersion":"24.14.1","dependencies":{"hono":"^4.12.12","@mcp-ui/client":"^7.0.0","@hono/node-server":"^1.19.13","@modelcontextprotocol/sdk":"^1.29.0","@modelcontextprotocol/ext-apps":"^1.3.2"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","zod":"^4.3.6","vite":"^8.0.7","react":"^19.2.4","eslint":"^9.39.4","rimraf":"^6.1.3","globals":"^17.4.0","prettier":"^3.8.1","@hono/mcp":"^0.2.5","react-dom":"^19.2.4","@eslint/js":"^9.39.4","typescript":"^6.0.2","@types/node":"^25.5.2","npm-run-all":"^4.1.5","@types/react":"^19.2.14","@changesets/cli":"^2.30.0","@playwright/test":"^1.59.1","@types/react-dom":"^19.2.3","typescript-eslint":"^8.58.1","eslint-plugin-import":"^2.32.0","@arethetypeswrong/cli":"^0.18.2","vite-plugin-singlefile":"^2.3.2","eslint-plugin-react-hooks":"^7.0.1","@changesets/changelog-github":"^0.6.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0","@playwright/test":">=1.40.0"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@playwright/test":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mcp-impostor-host_0.1.0_1775776946613_0.6004118228086266","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@apollo/mcp-impostor-host","version":"0.2.0","license":"MIT","_id":"@apollo/mcp-impostor-host@0.2.0","maintainers":[{"name":"phryneas","email":"mail@lenzw.de"},{"name":"jerelmiller","email":"jerelmiller@gmail.com"}],"bin":{"serve-impostor-host":"bin/serve-impostor-host.js"},"dist":{"shasum":"ef29108f4af8b2aa65902cb0b44c772182b95e28","tarball":"https://registry.npmjs.org/@apollo/mcp-impostor-host/-/mcp-impostor-host-0.2.0.tgz","fileCount":62,"integrity":"sha512-Px/qu1BCbqQ0MALqfPBnSUTfB+FIj5U6lb8GYfUxDLidifIGMBzcI31O5eIYjkAkiElxhl4HCojS2zxHVrPaHw==","signatures":[{"sig":"MEUCIQDNM81pe4r/ilc58/RY46wJjFJB5kewYEBay5kJ5lmeIwIgfdfQT2xiW0Qm6SMDdHdAHvDBdrB32o3Vv8hVGie2lyE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":928506},"main":"dist/core/index.js","type":"module","types":"dist/core/index.d.ts","module":"dist/core/index.js","exports":{".":{"types":"./dist/core/index.d.ts","default":"./dist/core/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./playwright":{"types":"./dist/playwright/index.d.ts","default":"./dist/playwright/index.js"}},"gitHead":"bd25363a5a631d4c0df3fa6a61967a749fb5cddd","imports":{"#package.json":"./package.json"},"scripts":{"attw":"npm run build && attw --pack . --ignore-rules cjs-resolves-to-esm --profile node16","lint":"eslint .","test":"playwright test","build":"npm-run-all build:*","clean":"rimraf dist","format":"prettier --write .","prebuild":"npm run clean","build:lib":"tsc --build tsconfig.build.json","typecheck":"tsc --build tsconfig.json","format:check":"prettier --check .","build:harness":"vite build --mode harness","build:sandbox":"vite build --mode sandbox","changeset-publish":"npm run build && changeset publish"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1c422334-e40e-478a-a4e1-366427396069"}},"_npmVersion":"11.11.0","description":"A test host for MCP Apps — impersonates a real MCP Apps host (e.g. Claude Desktop) for end-to-end testing","directories":{},"_nodeVersion":"24.14.1","dependencies":{"hono":"^4.12.12","@mcp-ui/client":"^7.0.0","@hono/node-server":"^1.19.13","@modelcontextprotocol/sdk":"^1.29.0","@modelcontextprotocol/ext-apps":"^1.3.2"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","zod":"^4.3.6","vite":"^8.0.7","react":"^19.2.4","eslint":"^9.39.4","rimraf":"^6.1.3","globals":"^17.4.0","prettier":"^3.8.1","@hono/mcp":"^0.2.5","react-dom":"^19.2.4","@eslint/js":"^9.39.4","typescript":"^6.0.2","@types/node":"^25.5.2","npm-run-all":"^4.1.5","@types/react":"^19.2.14","@changesets/cli":"^2.30.0","@playwright/test":"^1.59.1","@types/react-dom":"^19.2.3","typescript-eslint":"^8.58.1","eslint-plugin-import":"^2.32.0","@arethetypeswrong/cli":"^0.18.2","vite-plugin-singlefile":"^2.3.2","eslint-plugin-react-hooks":"^7.0.1","@changesets/changelog-github":"^0.6.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0","@playwright/test":">=1.40.0"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@playwright/test":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mcp-impostor-host_0.2.0_1775796973792_0.5443461132171663","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@apollo/mcp-impostor-host","version":"0.2.1","license":"MIT","_id":"@apollo/mcp-impostor-host@0.2.1","maintainers":[{"name":"phryneas","email":"mail@lenzw.de"},{"name":"jerelmiller","email":"jerelmiller@gmail.com"}],"bin":{"serve-impostor-host":"bin/serve-impostor-host.js"},"dist":{"shasum":"bc12940c98b4871f0dc3cb87756dd205bd4c2556","tarball":"https://registry.npmjs.org/@apollo/mcp-impostor-host/-/mcp-impostor-host-0.2.1.tgz","fileCount":63,"integrity":"sha512-y6mFDqL4uoFSJ0y5MrykHuYQ8t14sR26XRMMXZUyI2I5vu+GJi3hj+DKg1U8xaV/2OehngEurc4ZvbX6+pgxuQ==","signatures":[{"sig":"MEUCICKwhCHlutBScZm/CL3Cd1fg1xdDf6vrtfit+SdBQg+9AiEApsVGebGRW+o31MCdPC6atKs4QB4fbiX3DV5eglWyFXw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":933465},"main":"dist/core/index.js","type":"module","types":"dist/core/index.d.ts","module":"dist/core/index.js","exports":{".":{"types":"./dist/core/index.d.ts","default":"./dist/core/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./playwright":{"types":"./dist/playwright/index.d.ts","default":"./dist/playwright/index.js"}},"gitHead":"9b4ee11b057178cd6d45182758d14025b4bd9dfd","imports":{"#package.json":"./package.json"},"scripts":{"attw":"npm run build && attw --pack . --ignore-rules cjs-resolves-to-esm --profile node16","lint":"eslint .","test":"playwright test","build":"npm-run-all build:*","clean":"rimraf dist","format":"prettier --write .","prebuild":"npm run clean","build:lib":"tsc --build tsconfig.build.json","typecheck":"tsc --build tsconfig.json","format:check":"prettier --check .","build:harness":"vite build --mode harness","build:sandbox":"vite build --mode sandbox","changeset-publish":"npm run build && changeset publish"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1c422334-e40e-478a-a4e1-366427396069"}},"_npmVersion":"11.11.0","description":"A test host for MCP Apps — impersonates a real MCP Apps host (e.g. Claude Desktop) for end-to-end testing","directories":{},"_nodeVersion":"24.14.1","dependencies":{"hono":"^4.12.12","@mcp-ui/client":"^7.0.0","@hono/node-server":"^1.19.13","@modelcontextprotocol/sdk":"^1.29.0","@modelcontextprotocol/ext-apps":"^1.3.2"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","zod":"^4.3.6","vite":"^8.0.7","react":"^19.2.4","eslint":"^9.39.4","rimraf":"^6.1.3","globals":"^17.4.0","prettier":"^3.8.1","@hono/mcp":"^0.2.5","react-dom":"^19.2.4","@eslint/js":"^9.39.4","typescript":"^6.0.2","@types/node":"^25.5.2","npm-run-all":"^4.1.5","@types/react":"^19.2.14","@changesets/cli":"^2.30.0","@playwright/test":"^1.59.1","@types/react-dom":"^19.2.3","typescript-eslint":"^8.58.1","eslint-plugin-import":"^2.32.0","@arethetypeswrong/cli":"^0.18.2","vite-plugin-singlefile":"^2.3.2","eslint-plugin-react-hooks":"^7.0.1","@changesets/changelog-github":"^0.6.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0","@playwright/test":">=1.40.0"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@playwright/test":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mcp-impostor-host_0.2.1_1775851508989_0.4226771835440446","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@apollo/mcp-impostor-host","version":"0.3.0","description":"A test host for MCP Apps — impersonates a real MCP Apps host (e.g. Claude Desktop) for end-to-end testing","license":"MIT","type":"module","main":"dist/core/index.js","module":"dist/core/index.js","types":"dist/core/index.d.ts","bin":{"serve-impostor-host":"bin/serve-impostor-host.js"},"imports":{"#package.json":"./package.json"},"repository":{"type":"git","url":"git+https://github.com/apollographql/mcp-impostor-host.git"},"exports":{".":{"types":"./dist/core/index.d.ts","default":"./dist/core/index.js"},"./playwright":{"types":"./dist/playwright/index.d.ts","default":"./dist/playwright/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"}},"scripts":{"clean":"rimraf dist","prebuild":"npm run clean","build":"npm-run-all build:*","build:lib":"tsc --build tsconfig.build.json","build:harness":"vite build --mode harness","build:sandbox":"vite build --mode sandbox","test":"playwright test","typecheck":"tsc --build tsconfig.json","format":"prettier --write .","format:check":"prettier --check .","attw":"npm run build && attw --pack . --ignore-rules cjs-resolves-to-esm --profile node16","lint":"eslint .","changeset-publish":"npm run build && changeset publish"},"peerDependencies":{"@playwright/test":">=1.40.0","react":"^19.0.0","react-dom":"^19.0.0"},"peerDependenciesMeta":{"@playwright/test":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true}},"devDependencies":{"@arethetypeswrong/cli":"^0.18.2","@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.30.0","@eslint/js":"^9.39.4","@hono/mcp":"^0.2.5","@playwright/test":"^1.59.1","@types/node":"^25.5.2","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","eslint":"^9.39.4","eslint-plugin-import":"^2.32.0","eslint-plugin-react-hooks":"^7.0.1","globals":"^17.4.0","npm-run-all":"^4.1.5","prettier":"^3.8.1","react":"^19.2.4","react-dom":"^19.2.4","rimraf":"^6.1.3","tsx":"^4.21.0","typescript":"^6.0.2","typescript-eslint":"^8.58.1","vite":"^8.0.7","vite-plugin-singlefile":"^2.3.2","zod":"^4.3.6"},"dependencies":{"@hono/node-server":"^1.19.13","@modelcontextprotocol/ext-apps":"^1.3.2","@modelcontextprotocol/sdk":"^1.29.0","hono":"^4.12.12"},"gitHead":"0b1fe2c7a49523039d7d13cbd09a616b06aad824","_id":"@apollo/mcp-impostor-host@0.3.0","bugs":{"url":"https://github.com/apollographql/mcp-impostor-host/issues"},"homepage":"https://github.com/apollographql/mcp-impostor-host#readme","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-5Waod/xzvD22Ac+/A7pdCJhBHAqu6hoT+GYZl2vppp3fw3kHxvg6E5thzCM4tc3lwS9b+kREY1GeDn3ywB4HJg==","shasum":"82a48ca336c6596018e5da4cdc32481bc550241e","tarball":"https://registry.npmjs.org/@apollo/mcp-impostor-host/-/mcp-impostor-host-0.3.0.tgz","fileCount":71,"unpackedSize":665933,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@apollo%2fmcp-impostor-host@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAuDWhO6ckGJkqGVgOGTKDnmY9ra6KnYdJhG8ElggPunAiAdQ0hTb/JDfp0tyr0Hysx9FDW9hfNxzleeGinkBbIFKw=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1c422334-e40e-478a-a4e1-366427396069"}},"directories":{},"maintainers":[{"name":"phryneas","email":"mail@lenzw.de"},{"name":"jerelmiller","email":"jerelmiller@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-impostor-host_0.3.0_1776195436122_0.20432897219016666"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-09T23:22:26.530Z","modified":"2026-04-14T19:37:16.587Z","0.1.0":"2026-04-09T23:22:26.857Z","0.2.0":"2026-04-10T04:56:13.969Z","0.2.1":"2026-04-10T20:05:09.155Z","0.3.0":"2026-04-14T19:37:16.299Z"},"license":"MIT","description":"A test host for MCP Apps — impersonates a real MCP Apps host (e.g. Claude Desktop) for end-to-end testing","maintainers":[{"name":"phryneas","email":"mail@lenzw.de"},{"name":"jerelmiller","email":"jerelmiller@gmail.com"}],"readme":"<header>\n  <div align=\"center\">\n    <a href=\"https://www.apollographql.com?utm_medium=github&utm_source=apollographql_apollo-client&utm_campaign=readme\"><img src=\"https://raw.githubusercontent.com/apollographql/apollo-client-devtools/main/assets/apollo-wordmark.svg\" height=\"100\" alt=\"Apollo Logo\"></a>\n  </div>\n  <h1 align=\"center\">@apollo/mcp-impostor-host</h1>\n</header>\n\nA test host that impersonates a real MCP Apps host (like Claude Desktop) so you can end-to-end test your Tool UIs without a real host.\n\n## Installation\n\n```sh\nnpm install --save-dev @apollo/mcp-impostor-host\n```\n\nIf you plan to use the Playwright test fixture, install Playwright as well:\n\n```sh\nnpm install --save-dev @playwright/test\nnpx playwright install\n```\n\n## Playwright Configuration\n\nThe package includes a server that serves the sandbox and a prebuilt test harness. Configure Playwright to start it automatically using the `webServer` option in your `playwright.config.ts`:\n\n```ts\nimport { defineConfig } from \"@playwright/test\";\n\nexport default defineConfig({\n  testDir: \"./e2e\",\n  webServer: [\n    {\n      command: \"npx serve-impostor-host --playwright\",\n      url: \"http://localhost:8080\",\n      reuseExistingServer: !process.env.CI,\n    },\n    {\n      // Start your MCP server as well\n      command: \"your-mcp-server-start-command\",\n      url: \"http://localhost:8000/health\",\n      reuseExistingServer: !process.env.CI,\n    },\n  ],\n});\n```\n\nBy default, the sandbox server runs on port `8080`. Set the `SANDBOX_PORT` environment variable to use a different port.\n\n## Usage\n\nImport `test` from `@apollo/mcp-impostor-host/playwright` instead of `@playwright/test`. This provides the `mcpHost` fixture for connecting to your MCP server and calling tools.\n\n### Calling a tool and asserting on the UI\n\n```ts\nimport { test } from \"@apollo/mcp-impostor-host/playwright\";\nimport { expect } from \"@playwright/test\";\n\ntest(\"displays weather results\", async ({ mcpHost }) => {\n  // First, connect to the MCP server\n  const connection = await mcpHost.connect({\n    url: \"http://localhost:3000/mcp\",\n  });\n\n  // Call a tool that includes a UI resource. The UI resource will automatically\n  // render for you by the test harness\n  const { result, input, appFrame } = await connection.callTool(\"weather\", {\n    city: \"Portland\",\n  });\n\n  // `result` is the tool call result.\n  expect(result.isError).toBeFalsy();\n\n  // `input` is the tool input provided to the tool call\n  expect(input).toEqual({ city: \"Portland\" });\n\n  // `appFrame` is the iframe locator for your app. Use it to make assertions\n  // about your UI\n  await expect(appFrame.locator(\"h1\")).toHaveText(\"Weather for Portland\");\n});\n```\n\n### Waiting for a message request\n\nWhen the MCP app sends a message back to the host via `app.sendMessage`, use `waitForMessageRequest` to assert on it. Messages are queued in order, so you can safely await them sequentially.\n\n```ts\ntest(\"sends a message when the user submits feedback\", async ({ mcpHost }) => {\n  const connection = await mcpHost.connect({\n    url: \"http://localhost:3000/mcp\",\n  });\n\n  const { appFrame } = await connection.callTool(\"weather\", {\n    city: \"Portland\",\n  });\n\n  await appFrame.getByRole(\"button\", { name: \"Inspire me\" }).click();\n\n  // Use `connection.waitForMessageRequest` to capture the message request\n  const message = await connection.waitForMessageRequest();\n\n  // Assert on the message that was sent from the app\n  expect(message).toEqual({\n    role: \"user\",\n    content: [\n      {\n        type: \"text\",\n        text: \"Based on what you know about me, give me some inspiration\",\n      },\n    ],\n  });\n});\n```\n\nAll received messages are also available on `connection.messageRequests` for retrospective assertions.\n\n### Waiting for an open link request\n\nWhen the MCP app requests to open a link via `app.openLink`, use `waitForOpenLinkRequest` to assert on it.\n\n```ts\ntest(\"opens documentation link\", async ({ mcpHost }) => {\n  const connection = await mcpHost.connect({\n    url: \"http://localhost:3000/mcp\",\n  });\n\n  const { appFrame } = await connection.callTool(\"weather\", {\n    city: \"Portland\",\n  });\n\n  await appFrame.getByRole(\"button\", { text: \"View full forecast\" }).click();\n\n  // Use `connection.waitForOpenLinkRequest` to capture the open link request\n  const link = await connection.waitForOpenLinkRequest();\n\n  expect(link).toEqual({\n    url: \"https://weather.example.com/portland\",\n  });\n});\n```\n\nAll received open link requests are available on `connection.openLinkRequests`.\n\n### Configuring host context\n\nUse `mcpHost.setHostContext` to configure the [host context](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx#host-context-in-mcpuiinitializeresult) provided to the app. Call it before or after a tool call. The initial host context is sent to the app as a response to its `ui/initialize` notification. Updates to host context are sent to the app as `ui/notifications/host-context-changed` notifications.\n\n`setHostContext` shallow-merges the provided values into the current host context. By default, the `platform`, `theme`, `locale`, and `timeZone` are detected and set from the browser environment.\n\n```ts\ntest(\"app responds to theme changes\", async ({ mcpHost }) => {\n  // Set initial host context before connecting\n  await mcpHost.setHostContext({ theme: \"dark\" });\n\n  const connection = await mcpHost.connect({\n    url: \"http://localhost:3000/mcp\",\n  });\n\n  const { appFrame } = await connection.callTool(\"my-tool\", {});\n\n  // Verify initial theme was received\n  await expect(appFrame.locator(\"#theme\")).toHaveText(\"dark\");\n\n  // Dynamically update — sends a host-context-changed notification to the app\n  await mcpHost.setHostContext({ theme: \"light\" });\n\n  await expect(appFrame.locator(\"#theme\")).toHaveText(\"light\");\n});\n```\n\n### Timeouts\n\nBoth `waitForMessageRequest` and `waitForOpenLinkRequest` default to a 5000ms timeout. Override it per-call:\n\n```ts\nconst message = await connection.waitForMessageRequest({ timeout: 10000 });\n```\n\n## Custom setups\n\nFor advanced use cases, the package also exports `Host`, `Sandbox`, and `useHostContext` for building your own host setup:\n\n```ts\nimport { Host } from \"@apollo/mcp-impostor-host\";\nimport { Sandbox, useHostContext } from \"@apollo/mcp-impostor-host/react\";\n```\n\n### `useHostContext`\n\nThe `useHostContext` hook provides sensible browser defaults and a shallow-merge setter for host context. This hook is provided as a convenience for managing host context, but is not required for `<Sandbox />` to function properly.\n\n```tsx\nimport { Sandbox, useHostContext } from \"@apollo/mcp-impostor-host/react\";\n\nfunction MyTestPage({ connection, execution }) {\n  const [hostContext, setHostContext] = useHostContext({ theme: \"dark\" });\n\n  return (\n    <>\n      <button onClick={() => setHostContext({ theme: \"light\" })}>\n        Switch to light mode\n      </button>\n      {connection && execution && (\n        <Sandbox\n          connection={connection}\n          execution={execution}\n          hostContext={hostContext}\n          url=\"http://localhost:8080/sandbox.html\"\n        />\n      )}\n    </>\n  );\n}\n```\n\nBy default, the `platform`, `theme`, `locale`, and `timeZone` are detected from the browser environment.\n","readmeFilename":"README.md","homepage":"https://github.com/apollographql/mcp-impostor-host#readme","repository":{"type":"git","url":"git+https://github.com/apollographql/mcp-impostor-host.git"},"bugs":{"url":"https://github.com/apollographql/mcp-impostor-host/issues"}}