{"_id":"@afjk/scene-sync-mcp","_rev":"7-252a90d86474f133952eed1b7ce70cd5","name":"@afjk/scene-sync-mcp","dist-tags":{"latest":"0.1.9"},"versions":{"0.1.1":{"name":"@afjk/scene-sync-mcp","version":"0.1.1","_id":"@afjk/scene-sync-mcp@0.1.1","maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"bin":{"scene-sync-mcp":"src/server.mjs","scene-sync-mcp-setup":"src/setup.mjs"},"dist":{"shasum":"aee2fb5314b625b691854f410d529aeb319699b3","tarball":"https://registry.npmjs.org/@afjk/scene-sync-mcp/-/scene-sync-mcp-0.1.1.tgz","fileCount":8,"integrity":"sha512-4Lfnc24vXXTS1fKGIcePP7fNT/wU09M0BqPpl1yKGeREOqDST0J8MboaFQmtA3SktKP46sJWfF/+RPmG45TGPA==","signatures":[{"sig":"MEUCIDLYg/SNJVT9jDVvC9RNvz8iMeOUvnYmfIGxCoT4WkTcAiEAi+sc2Z99W80HW8Jj8bm63HcRPiJ+sZY3M/mH2QM4xyo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":54582},"type":"module","engines":{"node":">=20"},"gitHead":"55a4412e8d600daf3d5feb4fb9f031b85e6c4457","scripts":{"dev":"node src/server.mjs","start":"node src/server.mjs","setup:codex":"node src/setup.mjs codex","setup:claude":"node src/setup.mjs claude","setup:codex:staging":"node src/setup.mjs codex --staging","setup:claude:staging":"node src/setup.mjs claude --staging"},"_npmUser":{"name":"afjk","email":"afjk01@gmail.com"},"_npmVersion":"9.6.7","description":"MCP server for afjk.jp Scene Sync","directories":{},"_nodeVersion":"22.22.2","dependencies":{"zod":"^3.24.0","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/scene-sync-mcp_0.1.1_1778028329225_0.8299186284229012","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@afjk/scene-sync-mcp","version":"0.1.4","_id":"@afjk/scene-sync-mcp@0.1.4","maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"homepage":"https://github.com/afjk/afjk.jp/tree/main/packages/scene-sync-mcp","bugs":{"url":"https://github.com/afjk/afjk.jp/issues"},"bin":{"scene-sync-mcp":"bin/scene-sync-mcp.js","scene-sync-mcp-setup":"bin/scene-sync-mcp-setup.js"},"dist":{"shasum":"2b8bad890c2e1733e6778541101c1723f82eaebb","tarball":"https://registry.npmjs.org/@afjk/scene-sync-mcp/-/scene-sync-mcp-0.1.4.tgz","fileCount":10,"integrity":"sha512-5pKK+8Q8tQqvIbQXn45v+fNwi6bmXVdNSgay4LrBwIokGYXKfCn86004hJ1Xji7xBd8K1cG/D4FuEdhQA9bEbQ==","signatures":[{"sig":"MEUCIDvP7BW505b0nGKmarV4WcjpQTDQNwrUeyU1YW0OBGcLAiEA+oknE5eg0DVvH8qGrr9fLl+pXemhdJ8VSCCI+rSais4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@afjk%2fscene-sync-mcp@0.1.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":54946},"type":"module","engines":{"node":">=20"},"gitHead":"8c53b975a0a4339eb88ad6c8ccf5ad524a2bd4f9","scripts":{"dev":"node src/server.mjs","start":"node src/server.mjs","setup:codex":"node src/setup.mjs codex","setup:claude":"node src/setup.mjs claude","setup:codex:staging":"node src/setup.mjs codex --staging","setup:claude:staging":"node src/setup.mjs claude --staging"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f7b01137-7c1e-425a-90ad-9c623dbaaf06"}},"repository":{"url":"git+https://github.com/afjk/afjk.jp.git","type":"git"},"_npmVersion":"11.13.0","description":"MCP server for afjk.jp Scene Sync","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^3.24.0","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/scene-sync-mcp_0.1.4_1778029535501_0.5804459730205664","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@afjk/scene-sync-mcp","version":"0.1.5","_id":"@afjk/scene-sync-mcp@0.1.5","maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"homepage":"https://github.com/afjk/afjk.jp/tree/main/packages/scene-sync-mcp","bugs":{"url":"https://github.com/afjk/afjk.jp/issues"},"bin":{"scene-sync-mcp":"bin/scene-sync-mcp.js","scene-sync-mcp-setup":"bin/scene-sync-mcp-setup.js"},"dist":{"shasum":"b87181414253fb924131842f70fe222d50141638","tarball":"https://registry.npmjs.org/@afjk/scene-sync-mcp/-/scene-sync-mcp-0.1.5.tgz","fileCount":11,"integrity":"sha512-p8ZbgDVFjRoAm6mumbhxnT33kuijcZd67PbkfHtF2hr56OmeWt+lJlShOnTohsVIA7WBQhlLuX7k7C4xYkgSZw==","signatures":[{"sig":"MEQCIFQKKIblu2IBtvdarvuHu8Pd0Qqb6d5/MS9lnYA+kC5EAiBlZ7yR9mtu5yg3B0o94hUfi2nv5V7KwSHCqTFvyUPFag==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@afjk%2fscene-sync-mcp@0.1.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":57583},"type":"module","engines":{"node":">=20"},"gitHead":"46334286384a71e8909e14f1ddfb8451f44c8f6f","scripts":{"dev":"node src/cli.mjs serve","start":"node src/cli.mjs serve","doctor":"node src/cli.mjs doctor","setup:codex":"node src/cli.mjs setup codex","setup:claude":"node src/cli.mjs setup claude","setup:codex:staging":"node src/cli.mjs setup codex --staging","setup:claude:staging":"node src/cli.mjs setup claude --staging"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f7b01137-7c1e-425a-90ad-9c623dbaaf06"}},"repository":{"url":"git+https://github.com/afjk/afjk.jp.git","type":"git"},"_npmVersion":"11.13.0","description":"MCP server for afjk.jp Scene Sync","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^3.24.0","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/scene-sync-mcp_0.1.5_1778030125192_0.3004071391315277","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@afjk/scene-sync-mcp","version":"0.1.6","_id":"@afjk/scene-sync-mcp@0.1.6","maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"homepage":"https://github.com/afjk/afjk.jp/tree/main/packages/scene-sync-mcp","bugs":{"url":"https://github.com/afjk/afjk.jp/issues"},"bin":{"scene-sync-mcp":"bin/scene-sync-mcp.js","scene-sync-mcp-setup":"bin/scene-sync-mcp-setup.js"},"dist":{"shasum":"a89b367aedabed4a4caefbadf6baab112a26e5b3","tarball":"https://registry.npmjs.org/@afjk/scene-sync-mcp/-/scene-sync-mcp-0.1.6.tgz","fileCount":11,"integrity":"sha512-+lfxDYIBCDrY9sP6PfMi132XleiRdLP7JZhjfFcfrXtMfvmAsZULkYIQgfhFvzTlsAVxaWT53kqiaXhBXfdPRg==","signatures":[{"sig":"MEUCIFT00shqvqwOk5krYE5//K8swkDEe4hWWgP+B/6/tP0mAiEAv76iGm0WIIoz+A4eJBM/OivZA8cI7V5B7QvEMHaHmIA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@afjk%2fscene-sync-mcp@0.1.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":59743},"type":"module","engines":{"node":">=20"},"gitHead":"a92e01f16783680f2517ddac869dde984c35c9bf","scripts":{"dev":"node src/cli.mjs serve","start":"node src/cli.mjs serve","doctor":"node src/cli.mjs doctor","setup:codex":"node src/cli.mjs setup codex","setup:claude":"node src/cli.mjs setup claude","setup:codex:staging":"node src/cli.mjs setup codex --staging","setup:claude:staging":"node src/cli.mjs setup claude --staging"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f7b01137-7c1e-425a-90ad-9c623dbaaf06"}},"repository":{"url":"git+https://github.com/afjk/afjk.jp.git","type":"git"},"_npmVersion":"11.13.0","description":"MCP server for afjk.jp Scene Sync","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^3.24.0","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/scene-sync-mcp_0.1.6_1778030978837_0.39711517939173446","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"@afjk/scene-sync-mcp","version":"0.1.7","_id":"@afjk/scene-sync-mcp@0.1.7","maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"homepage":"https://github.com/afjk/afjk.jp/tree/main/packages/scene-sync-mcp","bugs":{"url":"https://github.com/afjk/afjk.jp/issues"},"bin":{"scene-sync-mcp":"bin/scene-sync-mcp.js","scene-sync-mcp-setup":"bin/scene-sync-mcp-setup.js","scene-sync-mcp-graph-tools":"bin/scene-sync-mcp-graph-tools.js"},"dist":{"shasum":"90dd6236f0184a1bb0316f31024e0e736f0d7f85","tarball":"https://registry.npmjs.org/@afjk/scene-sync-mcp/-/scene-sync-mcp-0.1.7.tgz","fileCount":13,"integrity":"sha512-pAuxID1TPhiu4yqJx1rNjILtctzePwV9NtLRqpKN6S20zvTTX7qfZkM9dVXC7Y89/CRdgGtl467TSncRIzEYNg==","signatures":[{"sig":"MEYCIQDt0/WViRRXpfS/u0ocNP3Iy0vVcs5A9jq8SXOBUdl5WAIhAJUJF20kvYPLCzSvKqb/Sxowwez98vX2Y9DO4VNylMeM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@afjk%2fscene-sync-mcp@0.1.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":72761},"type":"module","engines":{"node":">=20"},"gitHead":"564bcec5a9117219d4d15537eede1ab401e6cc42","scripts":{"dev":"node src/cli.mjs serve","start":"node src/cli.mjs serve","doctor":"node src/cli.mjs doctor","setup:codex":"node src/cli.mjs setup codex","setup:claude":"node src/cli.mjs setup claude","setup:codex:staging":"node src/cli.mjs setup codex --staging","setup:claude:staging":"node src/cli.mjs setup claude --staging"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f7b01137-7c1e-425a-90ad-9c623dbaaf06"}},"repository":{"url":"git+https://github.com/afjk/afjk.jp.git","type":"git"},"_npmVersion":"11.15.0","description":"MCP server for afjk.jp Scene Sync","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^3.24.0","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/scene-sync-mcp_0.1.7_1779424783168_0.35861104636138874","host":"s3://npm-registry-packages-npm-production"}},"0.1.8":{"name":"@afjk/scene-sync-mcp","version":"0.1.8","_id":"@afjk/scene-sync-mcp@0.1.8","maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"homepage":"https://github.com/afjk/afjk.jp/tree/main/packages/scene-sync-mcp","bugs":{"url":"https://github.com/afjk/afjk.jp/issues"},"bin":{"scene-sync-mcp":"bin/scene-sync-mcp.js","scene-sync-mcp-setup":"bin/scene-sync-mcp-setup.js","scene-sync-mcp-graph-tools":"bin/scene-sync-mcp-graph-tools.js"},"dist":{"shasum":"0a8028f0c33d14c3c410101c3d55418088fd5a9f","tarball":"https://registry.npmjs.org/@afjk/scene-sync-mcp/-/scene-sync-mcp-0.1.8.tgz","fileCount":13,"integrity":"sha512-QCepAR6/P3lB+3yNHQX436QrC36k5mGBsLKuPyTTkfe5wXNZ/u4GMHw6xzVKzL6YmSpZwbaBSSesbzxFZxYphg==","signatures":[{"sig":"MEQCIF0X3Rz178BC7ux19tnEkmP/WK0B8Tod9PXjB0poTJRUAiBkXhD65l1b2sAMpIfDR7ZXvyYHiiCFqBpi/F/DOJnTmQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":77568},"type":"module","engines":{"node":">=20"},"gitHead":"f0ab4d05821ccde6a4f007045d875024c6f3fb8d","scripts":{"dev":"node src/cli.mjs serve","start":"node src/cli.mjs serve","doctor":"node src/cli.mjs doctor","setup:codex":"node src/cli.mjs setup codex","setup:claude":"node src/cli.mjs setup claude","setup:codex:staging":"node src/cli.mjs setup codex --staging","setup:claude:staging":"node src/cli.mjs setup claude --staging"},"_npmUser":{"name":"afjk","email":"afjk01@gmail.com"},"repository":{"url":"git+https://github.com/afjk/afjk.jp.git","type":"git"},"_npmVersion":"9.6.7","description":"MCP server for afjk.jp Scene Sync","directories":{},"_nodeVersion":"22.22.2","dependencies":{"zod":"^3.24.0","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/scene-sync-mcp_0.1.8_1779527330915_0.9749427213220088","host":"s3://npm-registry-packages-npm-production"}},"0.1.9":{"name":"@afjk/scene-sync-mcp","version":"0.1.9","description":"MCP server for afjk.jp Scene Sync","type":"module","repository":{"type":"git","url":"git+https://github.com/afjk/afjk.jp.git"},"homepage":"https://github.com/afjk/afjk.jp/tree/main/packages/scene-sync-mcp","bugs":{"url":"https://github.com/afjk/afjk.jp/issues"},"bin":{"scene-sync-mcp":"bin/scene-sync-mcp.js","scene-sync-mcp-setup":"bin/scene-sync-mcp-setup.js","scene-sync-mcp-graph-tools":"bin/scene-sync-mcp-graph-tools.js"},"engines":{"node":">=20"},"publishConfig":{"access":"public"},"dependencies":{"@modelcontextprotocol/sdk":"^1.29.0","zod":"^3.24.0"},"scripts":{"start":"node src/cli.mjs serve","dev":"node src/cli.mjs serve","test":"node --test src/*.test.mjs","doctor":"node src/cli.mjs doctor","setup:codex":"node src/cli.mjs setup codex","setup:codex:staging":"node src/cli.mjs setup codex --staging","setup:claude":"node src/cli.mjs setup claude","setup:claude:staging":"node src/cli.mjs setup claude --staging"},"gitHead":"9d2ed78acb5070a4e5e9f7e1933480e04295e4ba","_id":"@afjk/scene-sync-mcp@0.1.9","_nodeVersion":"22.22.2","_npmVersion":"9.6.7","dist":{"integrity":"sha512-QNJxquo7FHTOKrFZvvKvT0t07nB/uLJUHCU4l1lN0SCf/Q1vWXPjTKOSKcRQrCSWaW04HivmHtYS/QQmJIyckA==","shasum":"0e9dddb9a523d7210589258b95826ded35e4539f","tarball":"https://registry.npmjs.org/@afjk/scene-sync-mcp/-/scene-sync-mcp-0.1.9.tgz","fileCount":14,"unpackedSize":98514,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGxeOB+9aLjjxKEAiatjkrW/JzJTL5HYKvUpB4Vd9etPAiEA0qPO+47bIBwQ2h8DnNsL4sy1kIGAQc++syPjoUAJBZw="}]},"_npmUser":{"name":"afjk","email":"afjk01@gmail.com"},"directories":{},"maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/scene-sync-mcp_0.1.9_1779717205934_0.5275024106544806"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-06T00:45:29.159Z","modified":"2026-05-25T13:53:26.190Z","0.1.1":"2026-05-06T00:45:29.400Z","0.1.4":"2026-05-06T01:05:35.680Z","0.1.5":"2026-05-06T01:15:25.355Z","0.1.6":"2026-05-06T01:29:39.001Z","0.1.7":"2026-05-22T04:39:43.349Z","0.1.8":"2026-05-23T09:08:51.075Z","0.1.9":"2026-05-25T13:53:26.079Z"},"bugs":{"url":"https://github.com/afjk/afjk.jp/issues"},"homepage":"https://github.com/afjk/afjk.jp/tree/main/packages/scene-sync-mcp","repository":{"type":"git","url":"git+https://github.com/afjk/afjk.jp.git"},"description":"MCP server for afjk.jp Scene Sync","maintainers":[{"name":"afjk","email":"afjk01@gmail.com"}],"readme":"# Scene Sync MCP\n\nAn MCP server for controlling [afjk.jp](https://afjk.jp) Scene Sync from Claude Desktop, Claude Code, and Codex.\n\nScene Sync is a real-time 3D scene synchronization system. This MCP server lets AI models:\n- Redeem pairing codes to link to a user's Scene Sync room\n- Add and manipulate 3D objects (boxes, spheres, primitives, and image/video/text/GLB assets from URL)\n- Place objects precisely using world bounds, alignment, and size fitting helpers\n- Replace existing media/text panels with new content (with Undo/Redo support)\n- Inspect camera pose\n- Access browser operation history (undo/redo)\n- Focus the camera on objects\n- Update the scene skybox from an image URL\n- Take screenshots\n- Switch animation clips on animated GLB objects\n- Manage the link session\n\n## Installation\n\nScene Sync MCP is published to npm as `@afjk/scene-sync-mcp`.\n\n### Codex CLI\n\nRecommended:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup codex\n```\n\nCheck the resolved base URL and session file:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest doctor\n```\n\nFor staging:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup codex --staging\n```\n\n### Claude Desktop\n\nUpdate Claude Desktop config automatically:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup claude\n```\n\nThis command updates `claude_desktop_config.json` and adds or replaces the `scene-sync` entry while preserving your other MCP servers and preferences.\n\nTo print the JSON instead of writing it:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup claude --print\n```\n\nAdd to your `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"scene-sync\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@afjk/scene-sync-mcp@latest\"]\n    }\n  }\n}\n```\n\nThen fully quit and restart Claude Desktop. For Claude Desktop config path, see https://modelcontextprotocol.io/clients/claude/\n\nTo use staging or customize the session file location:\n\n```json\n{\n  \"mcpServers\": {\n    \"scene-sync\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@afjk/scene-sync-mcp@latest\"],\n      \"env\": {\n        \"SCENE_SYNC_BASE_URL\": \"https://afjk.jp/presence/api/ai\",\n        \"SCENE_SYNC_SESSION_FILE\": \"/Users/YOUR_NAME/.scene-sync-mcp/session.json\"\n      }\n    }\n  }\n}\n```\n\n### Setup Helpers\n\nSingle-command helpers:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup codex\n```\n\nPrint Claude Desktop config without writing:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup claude --print\n```\n\nShow local diagnostics:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest doctor\n```\n\nThe legacy `scene-sync-mcp-setup` binary still works, but the main `scene-sync-mcp` CLI is now the primary entrypoint.\n\nIf you prefer a local checkout instead of npm, use the package scripts:\n\n```bash\nnpm install\nnpm run setup:codex\n```\n\n### Local Development\n\nFor development or contributing to the MCP server itself:\n\n```bash\nnpm install\nnpm run start\n```\n\nTo use the local checkout with Claude Desktop:\n\n```json\n{\n  \"mcpServers\": {\n    \"scene-sync\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/packages/scene-sync-mcp/src/cli.mjs\", \"serve\"]\n    }\n  }\n}\n```\n\nTo register the local checkout with Codex:\n\n```bash\ncd packages/scene-sync-mcp\nnpm install\nnpm run setup:codex\n```\n\n## Quick Start\n\n1. Open https://afjk.jp/scenesync/ in your browser\n2. Click \"AIにリンク\" (Link with AI)\n3. Copy the 6-digit code\n4. Tell Claude: \"Scene Sync に 123456 のコードでリンクして\" (Link Scene Sync with code 123456)\n5. Ask: \"オレンジ色の箱を中央に置いて\" (Put an orange box in the center)\n\n## Tools\n\n### scene_sync_redeem\nRedeem a 6-digit pairing code. Call after the user clicks \"AIにリンク\" and provides the code.\n\nInput:\n```json\n{\n  \"code\": \"123456\"\n}\n```\n\n### scene_sync_status\nCheck current link status and expiration time.\n\n### scene_sync_get_scene\nGet the current scene state (objects and environment). May take up to 5 seconds.\n\nInput: `{}` (default) or `{ \"selectedOnly\": true }` to return only currently selected objects.\n\nWhen `selectedOnly: true`, the browser is queried for the current selection instead of fetching the full scene snapshot.\n\nReturned objects may include world-space bounds:\n\n```json\n{\n  \"bounds\": {\n    \"world\": {\n      \"min\": [0, 0, 0],\n      \"max\": [1, 1, 1],\n      \"center\": [0.5, 0.5, 0.5],\n      \"size\": [1, 1, 1]\n    }\n  }\n}\n```\n\n`bounds.world.size` is the actual size after scale is applied.\n\n### scene_sync_add_box\nAdd a box to the scene. High-level tool; use directly for requests like \"add a red cube\".\n\nInput:\n```json\n{\n  \"objectId\": \"my-box-1\",\n  \"name\": \"Red Box\",\n  \"position\": [0, 0.5, 0],\n  \"color\": \"#ff0000\"\n}\n```\n\nAll fields except `position` default intelligently if omitted.\n\n### scene_sync_add_sphere\nAdd a sphere to the scene (same input schema as add_box).\n\n### scene_sync_add_primitive\nAdvanced: generic tool for adding any primitive (box, sphere, cylinder, plane). Prefer `scene_sync_add_box` or `scene_sync_add_sphere` for common cases.\n\n### scene_sync_move_object\nMove an existing object to a new absolute position.\n\nInput:\n```json\n{\n  \"objectId\": \"my-box-1\",\n  \"position\": [1, 0.5, 0]\n}\n```\n\n### scene_sync_rotate_object\nRotate an object using a quaternion [x, y, z, w].\n\n### scene_sync_scale_object\nScale an object using [x, y, z] scale factors.\n\n### scene_sync_set_transform\nSet object position, rotation, and/or scale in one scene-delta update.\n\nInput:\n```json\n{\n  \"objectId\": \"my-box-1\",\n  \"position\": [0, 0.5, 0],\n  \"rotation\": [0, 0, 0, 1],\n  \"scale\": [1, 2, 1]\n}\n```\n\nAt least one of `position`, `rotation`, or `scale` is required.\n\n### scene_sync_align_bounds\nMove a source object by aligning one or more `bounds.world` anchors to another object or to explicit world coordinates.\n\nInput:\n```json\n{\n  \"sourceObjectId\": \"fox\",\n  \"axes\": {\n    \"y\": {\n      \"source\": \"min\",\n      \"value\": 0\n    }\n  }\n}\n```\n\n### scene_sync_fit_bounds_size\nScale an object so its current `bounds.world.size` matches a target real-world size.\n\nInput:\n```json\n{\n  \"objectId\": \"fox\",\n  \"size\": {\n    \"y\": 1\n  },\n  \"preserveAspect\": true\n}\n```\n\n### scene_sync_set_color\nChange the color of a primitive object.\n\n**Important:** The `primitive` parameter is required. If the primitive type is unknown, call `scene_sync_get_scene` first and inspect the object's `asset.primitive` field.\n\nInput:\n```json\n{\n  \"objectId\": \"my-box-1\",\n  \"color\": \"#00ff00\",\n  \"primitive\": \"box\"\n}\n```\n\n日本語: `primitive` は必須です。種類が不明な場合は、先に `scene_sync_get_scene` で対象 object の `asset.primitive` を確認してください。\n\n### scene_sync_add_glb_from_url\nAdd a GLB/glTF model from a publicly fetchable URL.\n\nInput:\n```json\n{\n  \"url\": \"https://example.com/model.glb\",\n  \"objectId\": \"ai-model-1\",\n  \"name\": \"Example Model\",\n  \"position\": [0, 0, 0],\n  \"rotation\": [0, 0, 0, 1],\n  \"scale\": [1, 1, 1]\n}\n```\n\nNotes:\n- The URL must be accessible from the browser.\n- CORS headers may be required depending on the hosting site.\n- Local file paths are not supported by this tool.\n- For local files, drag & drop them into the Scene Sync browser UI instead.\n\n### scene_sync_add_image_from_url\nAdd an image panel from a publicly fetchable URL.\n\nInput:\n```json\n{\n  \"url\": \"https://example.com/image.jpg\",\n  \"objectId\": \"ai-image-1\",\n  \"name\": \"Reference Image\",\n  \"position\": [0, 1.5, -2],\n  \"rotation\": [0, 0, 0, 1],\n  \"scale\": [2, 2, 1]\n}\n```\n\nNotes:\n- The URL must be accessible from the browser.\n- CORS headers may be required depending on the hosting site.\n\n### scene_sync_add_video_from_url\nAdd a video panel from a publicly fetchable URL.\n\nInput:\n```json\n{\n  \"url\": \"https://example.com/video.mp4\",\n  \"objectId\": \"ai-video-1\",\n  \"name\": \"Loop Video\",\n  \"position\": [0, 1.5, -2],\n  \"rotation\": [0, 0, 0, 1],\n  \"scale\": [2, 2, 1]\n}\n```\n\nNotes:\n- The URL must be accessible from the browser.\n- CORS headers may be required depending on the hosting site.\n\n### scene_sync_add_text_from_url\nFetch text from a publicly fetchable URL and add it as a text panel.\n\nInput:\n```json\n{\n  \"url\": \"https://example.com/notes.txt\",\n  \"objectId\": \"ai-text-1\",\n  \"name\": \"Remote Notes\",\n  \"position\": [0, 1.5, -2],\n  \"rotation\": [0, 0, 0, 1],\n  \"scale\": [2, 2, 1]\n}\n```\n\nNotes:\n- The URL must be accessible from the browser.\n- CORS headers may be required depending on the hosting site.\n- The browser fetches and interprets the remote text content.\n\n### scene_sync_set_skybox_from_image_url\nSet the scene skybox from a publicly fetchable image URL.\n\nInput:\n```json\n{\n  \"url\": \"https://example.com/panorama.jpg\"\n}\n```\n\nNotes:\n- This replaces the current browser skybox/environment image.\n- The URL must be accessible from the browser.\n- CORS headers may be required depending on the hosting site.\n\n### scene_sync_get_camera_pose\nGet the current browser camera position and quaternion.\n\nInput: `{}`\n\nReturns camera position and quaternion.\n\n### scene_sync_get_history\nGet recent Scene Sync operation history.\n\nInput:\n```json\n{\n  \"count\": 10\n}\n```\n\nReturns the last N history entries from the browser.\n\n### scene_sync_replace_media\n\nReplace the content of a media panel with an image or video URL. If `objectId` is omitted, the currently selected object is used.\n\nInput:\n```json\n{\n  \"objectId\": \"media-panel-1\",\n  \"url\": \"https://example.com/image.png\",\n  \"mediaType\": \"image\",\n  \"name\": \"Updated Image\"\n}\n```\n\nOr for video:\n```json\n{\n  \"url\": \"https://example.com/video.mp4\",\n  \"mediaType\": \"video\"\n}\n```\n\nFields: `url` (required), `mediaType` (required, \"image\" or \"video\"), `objectId` (optional), `name` (optional).\n\nNotes:\n- Image and video media panels can be interchanged.\n- The URL must be accessible from the browser.\n- CORS headers may be required.\n\n### scene_sync_replace_text\n\nReplace the text content of a text panel. If `objectId` is omitted, the currently selected object is used.\n\nInput:\n```json\n{\n  \"objectId\": \"text-panel-1\",\n  \"text\": \"Hello Scene Sync\",\n  \"fontFamily\": \"system-sans\",\n  \"fontSize\": 32,\n  \"color\": \"#ffffff\",\n  \"align\": \"center\"\n}\n```\n\nFields: `text` (required), `objectId` (optional), `name` (optional), `fontFamily` (optional, \"system-sans\" / \"serif\" / \"monospace\" / \"japanese-sans\" / \"japanese-serif\"), `fontSize` (optional, pixels), `fontWeight` (optional), `fontStyle` (optional, \"normal\" / \"italic\"), `color` (optional), `backgroundColor` (optional), `align` (optional, \"left\" / \"center\" / \"right\").\n\nNotes:\n- Unspecified text styling fields inherit from the existing asset.\n- If no existing styling exists, default values are used.\n\n### scene_sync_set_animation_clip\n\nSwitch an animated GLB object to a specific animation clip by name or index.\n\nFirst inspect selected object clips:\n\n````json\n{\n  \"tool\": \"scene_sync_get_selection\",\n  \"arguments\": {}\n}\n````\n\nThen switch clip:\n\n````json\n{\n  \"tool\": \"scene_sync_set_animation_clip\",\n  \"arguments\": {\n    \"objectId\": \"minotauros-001\",\n    \"clipName\": \"laugh\",\n    \"mode\": \"loop\"\n  }\n}\n````\n\nIf a clip name is ambiguous, for example `attack`, the browser returns candidates such as `attack_1`, `attack_2`, etc. Choose a specific one.\n\nInput:\n```json\n{\n  \"objectId\": \"minotauros-001\",\n  \"clipName\": \"laugh\",\n  \"mode\": \"loop\"\n}\n```\n\nOr by index:\n```json\n{\n  \"objectId\": \"minotauros-001\",\n  \"clip\": 7\n}\n```\n\nFields: `objectId` (required), `clipName` or `name` or `clip` (one required), `mode` (loop/once, default loop), `speed` (default 1), `enabled` (default true).\n\n### scene_sync_get_selection\n\nReturns the objects currently selected in the linked Scene Sync browser.\n\nThis is a generic current-selection API for external tools. Selection is browser-local/session-local state and is not persisted into the shared scene.\n\nInput: `{}`\n\nReturned objects may include world-space bounds (same structure as `scene_sync_get_scene`).\n\nUse cases:\n\n- align selected objects\n- distribute selected objects\n- randomize selected rotation or scale\n- apply a Loomlet graph to selected objects\n- run scoped edits from AI or CLI tools\n\n### Bounds-based placement tools\n\nSome tools use `bounds.world` from the current browser scene. These bounds are world-axis aligned bounding boxes after scale and rotation are applied. This means rotated objects are measured as world-axis AABBs, not local oriented bounds.\n\nUse these tools for production-like placement tasks:\n\n- `scene_sync_set_transform`: update position, rotation, and scale together\n- `scene_sync_align_bounds`: align object bounds to another object or to a world coordinate\n- `scene_sync_fit_bounds_size`: scale an object to a target world-space size\n\nPlace an object on the floor at world Y=0:\n\n```json\n{\n  \"tool\": \"scene_sync_align_bounds\",\n  \"arguments\": {\n    \"sourceObjectId\": \"fox\",\n    \"axes\": {\n      \"y\": { \"source\": \"min\", \"value\": 0 }\n    }\n  }\n}\n```\n\nCenter an image panel on a wall and place it slightly in front:\n\n```json\n{\n  \"tool\": \"scene_sync_align_bounds\",\n  \"arguments\": {\n    \"sourceObjectId\": \"image-panel\",\n    \"targetObjectId\": \"wall\",\n    \"axes\": {\n      \"x\": { \"source\": \"center\", \"target\": \"center\" },\n      \"y\": { \"source\": \"center\", \"target\": \"center\" },\n      \"z\": { \"source\": \"min\", \"target\": \"max\", \"offset\": 0.01 }\n    }\n  }\n}\n```\n\nMake a GLB model 1 meter tall:\n\n```json\n{\n  \"tool\": \"scene_sync_fit_bounds_size\",\n  \"arguments\": {\n    \"objectId\": \"fox\",\n    \"size\": { \"y\": 1 },\n    \"preserveAspect\": true\n  }\n}\n```\n\n### scene_sync_undo\nUndo the last operation recorded in the Scene Sync history.\n\nInput: `{}`\n\n### scene_sync_redo\nRedo the last undone operation.\n\nInput: `{}`\n\nNote: Undo/Redo operates on the browser-side Scene Sync history. Some operations may not be undoable if they were not recorded in the browser history.\n\n### scene_sync_focus_object\nFocus the browser camera on an object (requires objectId).\n\n### scene_sync_screenshot\n\nTake a screenshot from the linked browser.\n\nBy default, this returns MCP image content so Claude/Codex can visually inspect the scene. Default size is optimized for WebSocket safety (768px, quality 0.7).\n\nInput:\n\n```json\n{\n  \"mode\": \"image\",\n  \"maxWidth\": 768,\n  \"quality\": 0.7\n}\n```\n\nFor higher resolution, you can specify up to 2048px:\n\n```json\n{\n  \"mode\": \"image\",\n  \"maxWidth\": 1024,\n  \"quality\": 0.75\n}\n```\n\nUse URL mode for compatibility/debugging:\n\n```json\n{\n  \"mode\": \"url\"\n}\n```\n\nFields: `mode` (optional, \"image\" or \"url\", defaults to \"image\"), `maxWidth` (optional, pixels, defaults to 768, max 2048), `quality` (optional, JPEG quality 0.1-1, defaults to 0.7 for image mode).\n\n#### Verifying image mode\n\n`mode: \"image\"` is the default for MCP clients, and `scene_sync_screenshot` has two return layers:\n\n- Browser / AI command layer: when `mode: \"image\"` is used, the browser returns JSON containing base64 image data.\n- MCP tool layer: the MCP server converts that base64 data into MCP image content so Claude, Codex, and other MCP clients can inspect the screenshot visually.\n\nWhen testing MCP behavior, call the registered MCP tool directly. Do not only call `scene-sync-client.mjs` or `aiCommand('screenshot')` directly, because that only verifies the lower-level JSON/base64 transport.\n\nA successful MCP tool result should contain image content followed by metadata text:\n\n```text\ncontent[0].type: image\ncontent[0].mimeType: image/jpeg\ncontent[1].type: text\n```\n\nExample metadata:\n\n```json\n{\n  \"ok\": true,\n  \"action\": \"screenshot\",\n  \"mode\": \"image\",\n  \"mimeType\": \"image/jpeg\",\n  \"width\": 1024,\n  \"height\": 598,\n  \"userPresent\": true\n}\n```\n\n### scene_sync_revoke\nRevoke the current link. The user must redeem a new code to continue.\n\n## Response Contract\n\n- Success responses are JSON text with `ok: true` and tool-specific fields.\n- Error responses are JSON text with `ok: false` and `error: { code, message, retryable }`.\n- `validation_error` and `unauthorized` are non-retryable.\n- Browser command failures can still appear inside a successful wrapper response\n  as `result.ok: false`; check the nested result when verification matters.\n- Browser command success responses pass through room context fields such as\n  `room`, `peers`, `userPresent`, and `targetPeerId` when the backend returns\n  them.\n\n## Environment Variables\n\n### SCENE_SYNC_BASE_URL\nDefault: `https://afjk.jp/presence/api/ai`\n\nAPI endpoint base URL.\n\n### SCENE_SYNC_SESSION_FILE\nDefault: `$HOME/.config/scene-sync-mcp/session.json`\n\nSession is persisted to this JSON file by default.\n\nExample (note: use full path, not `~`):\n```bash\nexport SCENE_SYNC_SESSION_FILE=$HOME/.config/scene-sync-mcp/session.json\n# or\nexport SCENE_SYNC_SESSION_FILE=/Users/yourname/.config/scene-sync-mcp/session.json\n```\n\n**Important:** Node.js does not automatically expand `~`. Use `$HOME` or full path instead.\n\nOverride it only when you need a custom location.\n\n### SCENE_SYNC_DEFAULT_COLOR\nDefault: `#ff8800`\n\nDefault color for new objects if color is not specified.\n\n### SCENE_SYNC_ENABLE_RAW_TOOLS\nDefault: `false`\n\nIf `true`, enables the `scene_sync_raw_broadcast` developer tool. Use only for advanced debugging.\n\n```bash\nexport SCENE_SYNC_ENABLE_RAW_TOOLS=true\n```\n\n## Browser AI Command parity\n\nBrowser AI commands in `html/assets/js/scenesync/scene.js` should stay in sync with MCP tools.\n\n| Browser AI Command | MCP Tool | Status |\n|---|---|---|\n| `getCameraPose` | `scene_sync_get_camera_pose` | supported |\n| `focusObject` | `scene_sync_focus_object` | supported |\n| `screenshot` | `scene_sync_screenshot` | supported |\n| `uploadGlbFromUrl` | `scene_sync_add_glb_from_url` | supported |\n| `addImageFromUrl` | `scene_sync_add_image_from_url` | supported |\n| `addVideoFromUrl` | `scene_sync_add_video_from_url` | supported |\n| `addTextFromUrl` | `scene_sync_add_text_from_url` | supported |\n| `setSkyboxFromImageUrl` | `scene_sync_set_skybox_from_image_url` | supported |\n| `getHistory` | `scene_sync_get_history` | supported |\n| `undo` | `scene_sync_undo` | supported |\n| `redo` | `scene_sync_redo` | supported |\n| `getSelection` | `scene_sync_get_selection` | supported |\n| `setAnimationClip` | `scene_sync_set_animation_clip` | supported |\n\nWhen adding a new browser AI command:\n\n- Add command handling in `handleAiCommand()`\n- Add matching MCP tool in `packages/scene-sync-mcp/src/server.mjs`\n- Add README documentation for the MCP tool\n- Update this parity table\n- Confirm tool responses do not expose `sessionId`\n- Confirm errors are handled by `assertAiCommandOk()`\n\n## Behavior Policy\n\n- **For clear requests** (e.g., \"add a red cube\"), call `add_box`/`add_sphere` directly without checking the scene first.\n- **Before modifying existing objects**, call `get_scene` first if the target is ambiguous.\n- **Do not remove objects** without explicit user confirmation (removal tool not yet implemented).\n- **Use `ai-` prefix** for object IDs created by AI to distinguish from user-created objects.\n- **Prefer high-level tools** (`add_box`, `add_sphere`) over `add_primitive`.\n- **focus_object requires objectId** — do not call without it.\n\n## Coordinate System\n\n- **Y-up**, meters\n- **Floor is at y=0**\n- Position y is the object center (so a 1m box on the floor has y=0.5)\n- Position: [x, y, z]\n- Rotation: [qx, qy, qz, qw] quaternion\n\n## Security\n\n- **sessionId** is stored only inside the local MCP server process.\n- Session is persisted by default to `SCENE_SYNC_SESSION_FILE`.\n- Destructive tools (remove, batch operations) are not enabled in this MVP.\n- `scene_sync_raw_broadcast` is disabled by default.\n- The server does not expose sessionId in tool responses.\n\n## Troubleshooting\n\n### \"Not linked. Ask the user to press AIにリンク...\"\nThe user has not yet redeemed a pairing code. Ask them to:\n1. Open https://afjk.jp/scenesync/\n2. Click \"AIにリンク\"\n3. Copy the 6-digit code\n4. Provide the code to call `scene_sync_redeem`\n\n### \"Link expired\"\nThe pairing code has expired. Ask the user to repeat the link flow above.\n\nThese cases map to `error.code = unauthorized` when they are raised by a tool\nthat requires an active link.\n\n### \"userPresent=false\"\nThe Scene Sync room is open in the browser, but the user may not be actively viewing it. Ask them to focus the browser window.\n\n### Large get_scene responses\nIf `get_scene` returns many objects, the response is automatically summarized to show the first 50 object IDs.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run server\nnpm run start\n\n# Or watch mode (if added to scripts)\nnpm run dev\n```\n\nFor testing with Claude Desktop, modify your config to point to the local directory:\n\n```json\n{\n  \"mcpServers\": {\n    \"scene-sync\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/packages/scene-sync-mcp/src/cli.mjs\", \"serve\"]\n    }\n  }\n}\n```\n\n## Maintainer: Publishing to npm\n\nTo release a new version to npm:\n\n### 1. Update the package version\n\n```bash\ncd packages/scene-sync-mcp\nnpm version patch --no-git-tag-version\n# or: npm version minor --no-git-tag-version\n```\n\n### 2. Commit the version bump\n\n```bash\ncd ../..\ngit add packages/scene-sync-mcp/package.json packages/scene-sync-mcp/package-lock.json\ngit commit -m \"Release scene-sync-mcp v0.x.x\"\n```\n\n### 3. Create and push a release tag\n\n```bash\ngit tag scene-sync-mcp-v0.x.x\ngit push origin main\ngit push origin scene-sync-mcp-v0.x.x\n```\n\nThe GitHub Actions workflow `publish-scene-sync-mcp.yml` will automatically:\n- Run syntax checks and tests\n- Publish the package to npm using Trusted Publishing (OIDC)\n\nThe package will be available on npm at `@afjk/scene-sync-mcp` and can be used immediately with:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup codex\n```\n\nFor Claude Desktop:\n\n```bash\nnpx -y @afjk/scene-sync-mcp@latest setup claude\n```\n\n## Manual Test Checklist\n\n1. ✅ Start Scene Sync in browser\n2. ✅ Press \"AIにリンク\" and note the code\n3. ✅ Register MCP in Codex: `npx -y @afjk/scene-sync-mcp@latest setup codex`\n4. ✅ Or print Claude Desktop config: `npx -y @afjk/scene-sync-mcp@latest setup claude`\n5. ✅ Tell Claude or Codex: \"Scene Sync に [コード] でリンク\"\n6. ✅ Ask: \"オレンジ色の箱を中央に置いて\"\n7. ✅ Confirm box appears in browser\n8. ✅ Ask: \"その箱にカメラをフォーカス\"\n9. ✅ Confirm camera focuses on box\n10. ✅ Ask: \"スクリーンショットを撮ってください\"\n11. ✅ Ask: \"リンクを解除\"\n12. ✅ Verify `scene_sync_status` returns \"Not linked\"\n\n## License\n\nPart of afjk.jp. See repository for license details.\n","readmeFilename":"README.md"}