conduit-mcp 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/bridge.ts","../src/protocol.ts","../src/utils/logger.ts","../src/tools/explore.ts","../src/utils/tokens.ts","../src/utils/formatting.ts","../src/tools/instances.ts","../src/tools/scripts.ts","../src/tools/playtest.ts","../src/tools/environment.ts","../src/tools/assets.ts","../src/tools/utility.ts","../src/context/api-data.json","../src/context/api-index.ts","../src/tools/studio.ts","../src/tools/builds.ts","../src/utils/builds.ts","../src/tools/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { Bridge } from \"./bridge.js\";\nimport { registerAllTools, type ToolRegistrationOptions } from \"./tools/index.js\";\nimport { log } from \"./utils/logger.js\";\nimport type { StudioInfo } from \"./protocol.js\";\n\nexport interface ServerOptions {\n mode?: \"full\" | \"inspector\";\n withCloud?: boolean;\n withRojo?: boolean;\n}\n\nexport async function startServer(\n port: number = 3200,\n options: ServerOptions = {},\n): Promise<void> {\n const bridge = new Bridge(port);\n\n const server = new McpServer(\n {\n name: \"conduit-mcp\",\n version: \"2.0.0\",\n },\n {\n instructions: [\n \"Conduit bridges AI assistants to Roblox Studio via WebSocket.\",\n \"The Conduit plugin must be running in Roblox Studio and connected.\",\n \"\",\n \"Workflow tips:\",\n \"- Use `explore` first to understand the DataModel before making changes.\",\n \"- Use `read_script` to read source before editing with `edit_script`.\",\n \"- All mutations are undoable via Ctrl+Z in Studio (ChangeHistoryService).\",\n \"- Use `lookup_api` to check Roblox API signatures before writing Luau code.\",\n \"- Batch operations: `create` and `modify` accept arrays of operations.\",\n \"- Token budgets: pass `maxTokens` to limit response size on large DataModels.\",\n \"- Use `query` to find instances by class, tag, or attribute.\",\n \"- Use `query --action scripts` to grep across all script sources.\",\n \"- Use `execute_lua` as an escape hatch for anything tools don't cover.\",\n \"- Use `explore --action set_selection` to select instances in Studio.\",\n \"\",\n \"Multi-Studio:\",\n \"- Multiple Studio instances can connect simultaneously.\",\n \"- Use `list_studios` to see connected instances and `set_active_studio` to switch.\",\n \"- With a single Studio, routing is automatic.\",\n ].join(\"\\n\"),\n },\n );\n\n const toolOptions: ToolRegistrationOptions = {\n mode: options.mode,\n withCloud: options.withCloud,\n withRojo: options.withRojo,\n };\n registerAllTools(server, bridge, toolOptions);\n\n bridge.on(\"studio-connected\", (info: StudioInfo) => {\n log.info(\n `Roblox Studio connected: ${info.studioId}` +\n (info.placeName ? ` (${info.placeName})` : \"\"),\n );\n });\n\n bridge.on(\"studio-disconnected\", (info: StudioInfo) => {\n log.warn(\n `Roblox Studio disconnected: ${info.studioId}` +\n (info.placeName ? ` (${info.placeName})` : \"\"),\n );\n });\n\n const actualPort = await bridge.start();\n log.info(`Bridge listening on port ${actualPort}`);\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n log.info(\"MCP server connected via stdio\");\n\n // Graceful shutdown\n const shutdown = async () => {\n log.info(\"Shutting down...\");\n await bridge.stop();\n await server.close();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n","import { EventEmitter } from \"node:events\";\nimport http from \"node:http\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport {\n type BridgeRequest,\n type PendingRequest,\n type StudioInfo,\n generateId,\n isHeartbeat,\n isStudioRegistration,\n isBridgeError,\n isBridgeResponse,\n} from \"./protocol.js\";\nimport { log } from \"./utils/logger.js\";\n\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst HEARTBEAT_CHECK_INTERVAL_MS = 5_000;\nconst HEARTBEAT_TIMEOUT_MS = 15_000;\nconst LONG_POLL_TIMEOUT_MS = 25_000;\nconst MAX_PORT_RETRIES = 10;\n\ninterface StudioConnection {\n ws: WebSocket;\n info: StudioInfo;\n}\n\nexport class Bridge extends EventEmitter {\n private httpServer: http.Server | null = null;\n private wsServer: WebSocketServer | null = null;\n private studios = new Map<string, StudioConnection>();\n private activeStudioId: string | null = null;\n private pendingRequests = new Map<string, PendingRequest>();\n private lastHeartbeats = new Map<string, number>();\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private actualPort = 0;\n\n // HTTP-only studios (no WebSocket connection)\n private httpStudios = new Map<string, StudioInfo>();\n\n // Unregistered WebSocket connections waiting for a registration message\n private pendingWs = new Set<WebSocket>();\n\n // HTTP fallback state (per-studio)\n private httpPendingCommands = new Map<string, BridgeRequest[]>();\n private httpPollWaiters = new Map<\n string,\n Array<{ res: http.ServerResponse; timer: ReturnType<typeof setTimeout> }>\n >();\n\n constructor(private port: number = 3200) {\n super();\n }\n\n get isConnected(): boolean {\n const studio = this.getActiveStudio();\n return studio !== undefined && studio.ws.readyState === WebSocket.OPEN;\n }\n\n get listeningPort(): number {\n return this.actualPort;\n }\n\n // ── Public studio management ───────────────────────────────────\n\n getStudios(): StudioInfo[] {\n const wsStudios = Array.from(this.studios.values()).map((s) => s.info);\n const httpOnly = Array.from(this.httpStudios.values()).filter(\n (s) => !this.studios.has(s.studioId),\n );\n return [...wsStudios, ...httpOnly];\n }\n\n getActiveStudioId(): string | null {\n return this.activeStudioId;\n }\n\n setActiveStudio(studioId: string): void {\n if (!this.studios.has(studioId) && !this.httpStudios.has(studioId)) {\n throw new Error(\n `Studio \"${studioId}\" is not connected. Connected studios: ${\n this.getStudios().map((s) => s.studioId).join(\", \") || \"none\"\n }`,\n );\n }\n this.activeStudioId = studioId;\n log.info(`Active studio set to: ${studioId}`);\n }\n\n // ── Server lifecycle ───────────────────────────────────────────\n\n async start(): Promise<number> {\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const tryPort = (port: number) => {\n const server = http.createServer((req, res) =>\n this.handleHttp(req, res),\n );\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\" && attempts < MAX_PORT_RETRIES) {\n attempts++;\n tryPort(port + 1);\n } else {\n reject(err);\n }\n });\n\n server.listen(port, \"127.0.0.1\", () => {\n this.httpServer = server;\n this.actualPort = port;\n this.wsServer = new WebSocketServer({ server });\n this.wsServer.on(\"connection\", (ws) => this.handleWsConnection(ws));\n log.info(`Bridge listening on 127.0.0.1:${port}`);\n resolve(port);\n });\n };\n\n tryPort(this.port);\n });\n }\n\n async stop(): Promise<void> {\n // Reject all pending requests\n for (const [id, pending] of this.pendingRequests) {\n clearTimeout(pending.timer);\n pending.reject(new Error(\"Bridge shutting down\"));\n this.pendingRequests.delete(id);\n }\n\n // Close all studio connections\n for (const [, studio] of this.studios) {\n studio.ws.close();\n }\n this.studios.clear();\n this.httpStudios.clear();\n this.activeStudioId = null;\n\n // Close pending unregistered connections\n for (const ws of this.pendingWs) {\n ws.close();\n }\n this.pendingWs.clear();\n\n // Stop heartbeat\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n // Close HTTP long-poll waiters and reject their pending requests\n for (const [, waiters] of this.httpPollWaiters) {\n for (const waiter of waiters) {\n clearTimeout(waiter.timer);\n waiter.res.writeHead(503);\n waiter.res.end();\n }\n }\n this.httpPollWaiters.clear();\n this.httpPendingCommands.clear();\n\n // Close servers\n await new Promise<void>((resolve) => {\n if (this.wsServer) {\n this.wsServer.close(() => {\n this.wsServer = null;\n if (this.httpServer) {\n this.httpServer.close(() => {\n this.httpServer = null;\n resolve();\n });\n } else {\n resolve();\n }\n });\n } else if (this.httpServer) {\n this.httpServer.close(() => {\n this.httpServer = null;\n resolve();\n });\n } else {\n resolve();\n }\n });\n }\n\n async send(\n method: string,\n params: Record<string, unknown>,\n ): Promise<unknown> {\n const id = generateId();\n const request: BridgeRequest = { id, method, params };\n const json = JSON.stringify(request);\n\n // Resolve which studio to target\n const studio = this.resolveTargetStudio();\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(\n new Error(\n `Request ${method} timed out after ${REQUEST_TIMEOUT_MS}ms — is the Conduit plugin running in Roblox Studio?`,\n ),\n );\n }, REQUEST_TIMEOUT_MS);\n\n this.pendingRequests.set(id, { resolve, reject, timer });\n\n if (studio) {\n studio.ws.send(json);\n } else {\n // Queue for HTTP fallback using active studio ID\n const studioId = this.activeStudioId ?? \"_default\";\n const queue = this.httpPendingCommands.get(studioId) ?? [];\n queue.push(request);\n this.httpPendingCommands.set(studioId, queue);\n this.flushHttpPollers(studioId);\n }\n });\n }\n\n // ── Internal helpers ───────────────────────────────────────────\n\n private getActiveStudio(): StudioConnection | undefined {\n if (this.activeStudioId) {\n return this.studios.get(this.activeStudioId);\n }\n return undefined;\n }\n\n private resolveTargetStudio(): StudioConnection | undefined {\n // If active studio is set and connected, use it\n const active = this.getActiveStudio();\n if (active && active.ws.readyState === WebSocket.OPEN) {\n return active;\n }\n\n // Auto-select if exactly one studio is connected\n if (this.studios.size === 1) {\n const [studioId, studio] = this.studios.entries().next().value!;\n if (studio.ws.readyState === WebSocket.OPEN) {\n this.activeStudioId = studioId;\n return studio;\n }\n }\n\n // No valid WebSocket target — will fall through to HTTP fallback\n if (this.studios.size === 0) {\n return undefined;\n }\n\n // Multiple studios, none active\n throw new Error(\n `Multiple Studio instances connected but none is active. Use set_active_studio to choose one. Connected: ${Array.from(\n this.studios.values(),\n )\n .map((s) => `${s.info.studioId} (${s.info.placeName ?? \"unknown\"})`)\n .join(\", \")}`,\n );\n }\n\n // ── WebSocket handling ─────────────────────────────────────────\n\n private handleWsConnection(ws: WebSocket): void {\n log.info(\"New WebSocket connection — waiting for registration\");\n this.pendingWs.add(ws);\n\n const onFirstMessage = (data: Buffer | string) => {\n try {\n const msg = JSON.parse(data.toString());\n\n if (isStudioRegistration(msg)) {\n ws.removeListener(\"message\", onFirstMessage);\n this.pendingWs.delete(ws);\n this.registerStudio(ws, {\n studioId: msg.studioId,\n placeId: msg.placeId,\n placeName: msg.placeName,\n connectedAt: Date.now(),\n });\n return;\n }\n\n // Legacy plugin (no registration) — assign synthetic ID\n ws.removeListener(\"message\", onFirstMessage);\n this.pendingWs.delete(ws);\n const syntheticId = \"studio-1\";\n log.info(\n \"Legacy plugin detected (no registration), assigning ID: \" +\n syntheticId,\n );\n this.registerStudio(ws, {\n studioId: syntheticId,\n connectedAt: Date.now(),\n });\n // Re-process the message we just received\n this.handlePluginMessage(msg);\n } catch (err) {\n log.warn(\"Failed to parse first plugin message:\", err);\n }\n };\n\n ws.on(\"message\", onFirstMessage);\n\n ws.on(\"close\", () => {\n // If it closed before registering\n this.pendingWs.delete(ws);\n });\n\n ws.on(\"error\", (err) => {\n log.warn(\"WebSocket error:\", err.message);\n });\n }\n\n private registerStudio(ws: WebSocket, info: StudioInfo): void {\n const { studioId } = info;\n\n // If this studioId already exists, close the old connection\n const existing = this.studios.get(studioId);\n if (existing) {\n log.warn(`Studio \"${studioId}\" reconnected — closing old connection`);\n existing.ws.close();\n }\n\n this.studios.set(studioId, { ws, info });\n this.lastHeartbeats.set(studioId, Date.now());\n\n // Auto-activate the first studio\n if (this.activeStudioId === null) {\n this.activeStudioId = studioId;\n }\n\n this.emit(\"studio-connected\", info);\n log.info(\n `Studio registered: ${studioId}` +\n (info.placeName ? ` (${info.placeName})` : \"\"),\n );\n\n this.startHeartbeatMonitor();\n\n ws.on(\"message\", (data) => {\n try {\n const msg = JSON.parse(data.toString());\n if (isHeartbeat(msg)) {\n this.lastHeartbeats.set(studioId, Date.now());\n return;\n }\n this.handlePluginMessage(msg);\n } catch (err) {\n log.warn(\"Failed to parse plugin message:\", err);\n }\n });\n\n ws.on(\"close\", () => {\n const current = this.studios.get(studioId);\n if (current && current.ws === ws) {\n this.studios.delete(studioId);\n this.lastHeartbeats.delete(studioId);\n this.emit(\"studio-disconnected\", info);\n log.info(`Studio disconnected: ${studioId}`);\n\n // If the active studio disconnected, auto-switch\n if (this.activeStudioId === studioId) {\n if (this.studios.size === 1) {\n this.activeStudioId = this.studios.keys().next().value!;\n log.info(\n `Auto-switched active studio to: ${this.activeStudioId}`,\n );\n } else {\n this.activeStudioId = null;\n }\n }\n\n if (this.studios.size === 0) {\n this.stopHeartbeatMonitor();\n }\n }\n });\n }\n\n private handlePluginMessage(msg: unknown): void {\n if (isBridgeResponse(msg)) {\n const pending = this.pendingRequests.get(msg.id);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingRequests.delete(msg.id);\n pending.resolve(msg.result);\n }\n return;\n }\n\n if (isBridgeError(msg)) {\n const pending = this.pendingRequests.get(msg.id);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingRequests.delete(msg.id);\n pending.reject(new Error(`${msg.error.code}: ${msg.error.message}`));\n }\n return;\n }\n\n log.debug(\"Unknown message from plugin:\", msg);\n }\n\n private startHeartbeatMonitor(): void {\n if (this.heartbeatTimer) return; // already running\n this.heartbeatTimer = setInterval(() => {\n const now = Date.now();\n for (const [studioId, lastBeat] of this.lastHeartbeats) {\n if (now - lastBeat > HEARTBEAT_TIMEOUT_MS) {\n const studio = this.studios.get(studioId);\n if (studio) {\n log.warn(\n `Heartbeat timeout for studio \"${studioId}\" — disconnecting`,\n );\n studio.ws.terminate();\n } else if (this.httpStudios.has(studioId)) {\n log.warn(\n `Heartbeat timeout for HTTP studio \"${studioId}\" — evicting`,\n );\n const info = this.httpStudios.get(studioId)!;\n this.httpStudios.delete(studioId);\n this.lastHeartbeats.delete(studioId);\n this.emit(\"studio-disconnected\", info);\n if (this.activeStudioId === studioId) {\n const remaining = this.getStudios();\n this.activeStudioId =\n remaining.length > 0 ? remaining[0].studioId : null;\n }\n }\n }\n }\n }, HEARTBEAT_CHECK_INTERVAL_MS);\n }\n\n private stopHeartbeatMonitor(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n // ── HTTP fallback handling ─────────────────────────────────────\n\n private handleHttp(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): void {\n // CORS headers for Studio plugin\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const parsedUrl = new URL(req.url ?? \"/\", `http://127.0.0.1`);\n const pathname = parsedUrl.pathname;\n\n if (req.method === \"GET\" && pathname === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n status: \"ok\",\n connected: this.isConnected,\n port: this.actualPort,\n studios: this.getStudios(),\n }),\n );\n return;\n }\n\n if (req.method === \"GET\" && pathname === \"/poll\") {\n const studioId =\n parsedUrl.searchParams.get(\"studioId\") ??\n this.activeStudioId ??\n \"_default\";\n this.handlePoll(studioId, res);\n return;\n }\n\n if (req.method === \"POST\" && pathname === \"/result\") {\n this.handleResult(req, res);\n return;\n }\n\n res.writeHead(404);\n res.end(\"Not found\");\n }\n\n private handlePoll(studioId: string, res: http.ServerResponse): void {\n // Register this studio via HTTP if not already known\n if (!this.studios.has(studioId) && studioId !== \"_default\") {\n if (!this.httpStudios.has(studioId)) {\n const info: StudioInfo = {\n studioId,\n connectedAt: Date.now(),\n };\n this.httpStudios.set(studioId, info);\n this.emit(\"studio-connected\", info);\n log.info(`HTTP-only studio registered: ${studioId}`);\n }\n this.lastHeartbeats.set(studioId, Date.now());\n if (this.activeStudioId === null) {\n this.activeStudioId = studioId;\n }\n }\n\n // Update heartbeat for HTTP-connected studios\n this.lastHeartbeats.set(studioId, Date.now());\n\n // If there are pending commands for this studio, send the oldest one\n const queue = this.httpPendingCommands.get(studioId) ?? [];\n if (queue.length > 0) {\n const cmd = queue.shift()!;\n if (queue.length === 0) {\n this.httpPendingCommands.delete(studioId);\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(cmd));\n return;\n }\n\n // Also check the default queue for backward compatibility\n if (studioId !== \"_default\") {\n const defaultQueue = this.httpPendingCommands.get(\"_default\") ?? [];\n if (defaultQueue.length > 0) {\n const cmd = defaultQueue.shift()!;\n if (defaultQueue.length === 0) {\n this.httpPendingCommands.delete(\"_default\");\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(cmd));\n return;\n }\n }\n\n // Long-poll: hold connection until a command is available or timeout\n const timer = setTimeout(() => {\n const waiters = this.httpPollWaiters.get(studioId);\n if (waiters) {\n const idx = waiters.findIndex((w) => w.res === res);\n if (idx !== -1) waiters.splice(idx, 1);\n if (waiters.length === 0) this.httpPollWaiters.delete(studioId);\n }\n res.writeHead(204);\n res.end();\n }, LONG_POLL_TIMEOUT_MS);\n\n const waiters = this.httpPollWaiters.get(studioId) ?? [];\n waiters.push({ res, timer });\n this.httpPollWaiters.set(studioId, waiters);\n }\n\n private handleResult(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): void {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", () => {\n try {\n const msg = JSON.parse(body);\n this.handlePluginMessage(msg);\n res.writeHead(200);\n res.end(\"ok\");\n } catch {\n res.writeHead(400);\n res.end(\"Invalid JSON\");\n }\n });\n }\n\n private flushHttpPollers(studioId: string): void {\n const waiters = this.httpPollWaiters.get(studioId) ?? [];\n const queue = this.httpPendingCommands.get(studioId) ?? [];\n\n while (waiters.length > 0 && queue.length > 0) {\n const waiter = waiters.shift()!;\n const cmd = queue.shift()!;\n clearTimeout(waiter.timer);\n waiter.res.writeHead(200, { \"Content-Type\": \"application/json\" });\n waiter.res.end(JSON.stringify(cmd));\n }\n\n if (waiters.length === 0) this.httpPollWaiters.delete(studioId);\n if (queue.length === 0) this.httpPendingCommands.delete(studioId);\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\n// ── Server → Plugin ──────────────────────────────────────────────\nexport interface BridgeRequest {\n id: string;\n method: string;\n params: Record<string, unknown>;\n sessionId?: string;\n}\n\n// ── Plugin → Server (success) ────────────────────────────────────\nexport interface BridgeResponse {\n id: string;\n result: unknown;\n tokenEstimate?: number;\n}\n\n// ── Plugin → Server (error) ──────────────────────────────────────\nexport interface BridgeError {\n id: string;\n error: { code: string; message: string };\n}\n\n// ── Plugin → Server (heartbeat) ──────────────────────────────────\nexport interface Heartbeat {\n type: \"heartbeat\";\n}\n\n// ── Plugin → Server (studio registration) ────────────────────────\nexport interface StudioRegistration {\n type: \"register\";\n studioId: string;\n placeId?: number;\n placeName?: string;\n}\n\n// ── Studio metadata ──────────────────────────────────────────────\nexport interface StudioInfo {\n studioId: string;\n placeId?: number;\n placeName?: string;\n connectedAt: number;\n}\n\nexport type PluginMessage =\n | BridgeResponse\n | BridgeError\n | Heartbeat\n | StudioRegistration;\n\n// ── Pending request tracking ─────────────────────────────────────\nexport interface PendingRequest {\n resolve: (value: unknown) => void;\n reject: (reason: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\n// ── Helpers ──────────────────────────────────────────────────────\nexport function generateId(): string {\n return randomUUID().slice(0, 8);\n}\n\nexport function isHeartbeat(msg: unknown): msg is Heartbeat {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n (msg as Heartbeat).type === \"heartbeat\"\n );\n}\n\nexport function isStudioRegistration(\n msg: unknown,\n): msg is StudioRegistration {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n (msg as StudioRegistration).type === \"register\" &&\n \"studioId\" in msg\n );\n}\n\nexport function isBridgeError(msg: unknown): msg is BridgeError {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"id\" in msg &&\n \"error\" in msg\n );\n}\n\nexport function isBridgeResponse(msg: unknown): msg is BridgeResponse {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"id\" in msg &&\n \"result\" in msg\n );\n}\n","/**\n * Logger that writes to stderr only — console.log is forbidden\n * because the MCP server communicates over stdout via stdio transport.\n */\nexport const log = {\n info: (...args: unknown[]) => console.error(\"[conduit]\", ...args),\n warn: (...args: unknown[]) => console.error(\"[conduit:warn]\", ...args),\n error: (...args: unknown[]) => console.error(\"[conduit:error]\", ...args),\n debug: (...args: unknown[]) => {\n if (process.env.CONDUIT_DEBUG) {\n console.error(\"[conduit:debug]\", ...args);\n }\n },\n};\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport {\n formatTree,\n formatInstanceList,\n applyTokenBudget,\n} from \"../utils/formatting.js\";\n\nexport function register(server: McpServer, bridge: Bridge): void {\n // ── explore ───────────────────────────────────────────────────────\n server.registerTool(\n \"explore\",\n {\n title: \"Explore Instance Tree\",\n description:\n \"Browse the Roblox instance hierarchy, get/set the current selection, or list top-level services.\\n\\n\" +\n \"Actions:\\n\" +\n \"- `tree` (default): Browse DataModel tree from a root path with depth, filter, and property options.\\n\" +\n \"- `get_selection`: Return the currently selected instances in Studio.\\n\" +\n \"- `set_selection`: Select specific instances in Studio by path.\\n\" +\n \"- `services`: List all top-level game services.\\n\" +\n \"- `state`: Get current Studio state (playtest status, place info, undo availability).\",\n inputSchema: z.object({\n action: z\n .enum([\"tree\", \"get_selection\", \"set_selection\", \"services\", \"state\"])\n .default(\"tree\")\n .describe(\"Action to perform\"),\n path: z\n .string()\n .default(\"game\")\n .describe(\"Root path to explore (for 'tree' action)\"),\n depth: z\n .number()\n .int()\n .min(0)\n .max(10)\n .default(2)\n .describe(\"How many levels deep to recurse (for 'tree' action)\"),\n filter: z\n .string()\n .optional()\n .describe(\"Only include instances whose ClassName matches (for 'tree' action)\"),\n includeProperties: z\n .boolean()\n .default(false)\n .describe(\"Include property values in output (for 'tree' action)\"),\n paths: z\n .array(z.string())\n .optional()\n .describe(\"Instance paths to select (for 'set_selection' action)\"),\n maxTokens: z\n .number()\n .optional()\n .describe(\"Maximum token budget for the response\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n if (params.action === \"get_selection\") {\n const result = (await bridge.send(\"get_selection\", {})) as {\n selection: Array<{ path: string; className: string }>;\n };\n const text = formatInstanceList(result.selection);\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n }\n\n if (params.action === \"set_selection\") {\n if (!params.paths || params.paths.length === 0) {\n return {\n content: [\n { type: \"text\", text: \"set_selection requires a non-empty `paths` array.\" },\n ],\n };\n }\n const result = (await bridge.send(\"set_selection\", {\n paths: params.paths,\n })) as { selected: number };\n return {\n content: [\n { type: \"text\", text: `Selected ${result.selected} instance(s).` },\n ],\n };\n }\n\n if (params.action === \"services\") {\n const result = (await bridge.send(\"get_services\", {})) as {\n services: Array<{ name: string; className: string }>;\n };\n const text =\n result.services.length === 0\n ? \"*No services found.*\"\n : result.services\n .map((s) => `- **${s.name}** \\`${s.className}\\``)\n .join(\"\\n\");\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n }\n\n if (params.action === \"state\") {\n const result = (await bridge.send(\"get_studio_state\", {})) as {\n isRunning: boolean;\n isClient: boolean;\n isServer: boolean;\n placeId: number;\n gameId: number;\n placeName?: string;\n canUndo?: boolean;\n canRedo?: boolean;\n };\n\n let mode = \"Edit\";\n if (result.isRunning) {\n if (result.isClient) mode = \"Playtest (Client)\";\n else if (result.isServer) mode = \"Playtest (Server)\";\n else mode = \"Running\";\n }\n\n const lines = [\n \"### Studio State\",\n `- **Mode:** ${mode}`,\n `- **Place ID:** ${result.placeId}${result.placeName ? ` — ${result.placeName}` : \"\"}`,\n `- **Game ID:** ${result.gameId}`,\n ];\n\n if (result.canUndo !== undefined) {\n lines.push(`- **Can Undo:** ${result.canUndo ? \"Yes\" : \"No\"}`);\n }\n if (result.canRedo !== undefined) {\n lines.push(`- **Can Redo:** ${result.canRedo ? \"Yes\" : \"No\"}`);\n }\n\n return {\n content: [{ type: \"text\", text: lines.join(\"\\n\") }],\n };\n }\n\n // Default: tree\n const result = await bridge.send(\"explore\", {\n path: params.path,\n depth: params.depth,\n filter: params.filter,\n includeProperties: params.includeProperties,\n });\n const text = formatTree(result as any, params.depth);\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n },\n );\n\n // ── get_info (merged get_instance_info + list_properties) ─────────\n server.registerTool(\n \"get_info\",\n {\n title: \"Get Instance Info\",\n description:\n \"Get detailed information about a single instance: class, parent, children count, properties, attributes, tags, and optionally a typed property list — all in one call.\",\n inputSchema: z.object({\n path: z\n .string()\n .describe(\"Path to the instance, e.g. 'game.Workspace.Part'\"),\n includeProperties: z\n .boolean()\n .default(true)\n .describe(\"Include property values\"),\n includeAttributes: z\n .boolean()\n .default(true)\n .describe(\"Include custom attributes\"),\n includeTags: z\n .boolean()\n .default(true)\n .describe(\"Include CollectionService tags\"),\n includePropertyList: z\n .boolean()\n .default(false)\n .describe(\"Include a typed list of all discoverable properties with types and values\"),\n propertyFilter: z\n .string()\n .optional()\n .describe(\"Filter property names by substring match (for property list)\"),\n maxTokens: z\n .number()\n .optional()\n .describe(\"Maximum token budget for the response\"),\n }),\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n const result = (await bridge.send(\"get_info\", {\n path: params.path,\n includeProperties: params.includeProperties,\n includeAttributes: params.includeAttributes,\n includeTags: params.includeTags,\n includePropertyList: params.includePropertyList,\n propertyFilter: params.propertyFilter,\n })) as {\n name: string;\n className: string;\n path: string;\n parent: string | null;\n childCount: number;\n properties?: Record<string, unknown>;\n attributes?: Record<string, unknown>;\n tags?: string[];\n propertyList?: Array<{ name: string; type: string; value: unknown }>;\n };\n\n const lines: string[] = [\n `### ${result.name} \\`${result.className}\\``,\n `- **Path:** \\`${result.path}\\``,\n `- **Parent:** ${result.parent ? `\\`${result.parent}\\`` : \"none\"}`,\n `- **Children:** ${result.childCount}`,\n ];\n\n if (result.tags && result.tags.length > 0) {\n lines.push(`- **Tags:** ${result.tags.join(\", \")}`);\n }\n\n if (result.attributes && Object.keys(result.attributes).length > 0) {\n lines.push(\"\", \"**Attributes:**\");\n for (const [k, v] of Object.entries(result.attributes)) {\n lines.push(`- ${k} = \\`${JSON.stringify(v)}\\``);\n }\n }\n\n if (result.properties && Object.keys(result.properties).length > 0) {\n lines.push(\"\", \"**Properties:**\");\n for (const [k, v] of Object.entries(result.properties)) {\n lines.push(`- ${k} = \\`${JSON.stringify(v)}\\``);\n }\n }\n\n if (result.propertyList && result.propertyList.length > 0) {\n lines.push(\"\", \"**Property List:**\");\n for (const p of result.propertyList) {\n lines.push(`- **${p.name}** \\`${p.type}\\` = \\`${JSON.stringify(p.value)}\\``);\n }\n }\n\n const text = lines.join(\"\\n\");\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n },\n );\n}\n","const CHARS_PER_TOKEN = 4;\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\nexport function truncateToTokenBudget(\n text: string,\n budget: number,\n): { text: string; truncated: boolean } {\n const maxChars = budget * CHARS_PER_TOKEN;\n if (text.length <= maxChars) {\n return { text, truncated: false };\n }\n\n const totalEstimate = estimateTokens(text);\n const truncated = text.slice(0, maxChars);\n const lastNewline = truncated.lastIndexOf(\"\\n\");\n const cleanCut = lastNewline > maxChars * 0.8 ? truncated.slice(0, lastNewline) : truncated;\n\n return {\n text:\n cleanCut +\n `\\n\\n---\\n*Truncated — showing ~${budget} of ~${totalEstimate} tokens. Narrow your query with filter, depth, or lineRange.*`,\n truncated: true,\n };\n}\n","import { estimateTokens, truncateToTokenBudget } from \"./tokens.js\";\n\nconst DEFAULT_TOKEN_BUDGET = 4000;\n\ninterface TreeNode {\n name: string;\n className: string;\n children?: TreeNode[];\n childCount?: number;\n properties?: Record<string, unknown>;\n}\n\nexport function formatTree(\n data: TreeNode,\n depth: number = 0,\n indent: string = \"\",\n): string {\n let line = `${indent}- **${data.name}** \\`${data.className}\\``;\n\n if (data.properties && Object.keys(data.properties).length > 0) {\n const props = Object.entries(data.properties)\n .map(([k, v]) => `${k}=${formatValue(v)}`)\n .join(\", \");\n line += ` (${props})`;\n }\n\n let result = line + \"\\n\";\n\n if (data.children && depth > 0) {\n for (const child of data.children) {\n result += formatTree(child, depth - 1, indent + \" \");\n }\n } else {\n const count = data.children?.length ?? data.childCount ?? 0;\n if (count > 0) {\n result += `${indent} *… ${count} children*\\n`;\n }\n }\n\n return result;\n}\n\nexport function formatInstanceList(\n instances: Array<{ path: string; className: string }>,\n): string {\n if (instances.length === 0) return \"*No instances found.*\";\n return instances.map((i) => `- **${i.path}** \\`${i.className}\\``).join(\"\\n\");\n}\n\nexport function formatScript(source: string, path: string): string {\n return `### ${path}\\n\\`\\`\\`lua\\n${source}\\n\\`\\`\\``;\n}\n\nexport function applyTokenBudget(\n text: string,\n maxTokens?: number,\n): string {\n const budget = maxTokens ?? DEFAULT_TOKEN_BUDGET;\n const { text: result } = truncateToTokenBudget(text, budget);\n return result;\n}\n\nfunction formatValue(v: unknown): string {\n if (v === null || v === undefined) return \"nil\";\n if (typeof v === \"string\") return `\"${v}\"`;\n if (typeof v === \"object\") {\n const obj = v as Record<string, unknown>;\n if (obj.Type) return `${obj.Type}(…)`;\n return JSON.stringify(v);\n }\n return String(v);\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport { applyTokenBudget } from \"../utils/formatting.js\";\n\nexport function registerReadOnly(server: McpServer, bridge: Bridge): void {\n registerQuery(server, bridge);\n}\n\nexport function register(server: McpServer, bridge: Bridge): void {\n registerQuery(server, bridge);\n registerWrite(server, bridge);\n}\n\nfunction registerQuery(server: McpServer, bridge: Bridge): void {\n // ── query (merged query_instances + grep_scripts) ─────────────────\n server.registerTool(\n \"query\",\n {\n title: \"Query Instances & Scripts\",\n description:\n \"Find instances or search script source code.\\n\\n\" +\n \"Actions:\\n\" +\n \"- `instances` (default): Find instances by class, tag, attribute, or name pattern.\\n\" +\n \"- `scripts`: Search across all script sources for a text pattern (grep).\",\n inputSchema: z.object({\n action: z\n .enum([\"instances\", \"scripts\"])\n .default(\"instances\")\n .describe(\"Query mode\"),\n // Instance query params\n basePath: z\n .string()\n .default(\"game\")\n .describe(\"Root path to search from\"),\n filters: z\n .object({\n className: z.string().optional().describe(\"Only include instances of this class\"),\n tag: z.string().optional().describe(\"Only include instances with this tag\"),\n attribute: z\n .object({\n name: z.string().describe(\"Attribute name\"),\n value: z.unknown().optional().describe(\"Required attribute value\"),\n })\n .optional()\n .describe(\"Filter by attribute\"),\n namePattern: z\n .string()\n .optional()\n .describe(\"Lua pattern to match against instance Name\"),\n })\n .optional()\n .describe(\"Filters for instance query (AND-combined)\"),\n limit: z.number().int().default(50).describe(\"Max results\"),\n // Script grep params\n pattern: z.string().optional().describe(\"Text pattern to search for (for 'scripts' action)\"),\n caseSensitive: z\n .boolean()\n .default(false)\n .describe(\"Case-sensitive search (for 'scripts' action)\"),\n contextLines: z\n .number()\n .int()\n .default(1)\n .describe(\"Lines of context around each match (for 'scripts' action)\"),\n maxTokens: z\n .number()\n .optional()\n .describe(\"Maximum token budget for the response\"),\n }),\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n if (params.action === \"scripts\") {\n if (!params.pattern) {\n return {\n content: [{ type: \"text\", text: \"scripts action requires a `pattern` parameter.\" }],\n };\n }\n const result = (await bridge.send(\"grep_scripts\", {\n basePath: params.basePath,\n pattern: params.pattern,\n caseSensitive: params.caseSensitive,\n contextLines: params.contextLines,\n limit: params.limit,\n })) as {\n results: Array<{\n scriptPath: string;\n lineNumber: number;\n line: string;\n context: string[];\n }>;\n totalMatches: number;\n scriptsSearched: number;\n };\n\n if (result.results.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: `*No matches found for \"${params.pattern}\" across ${result.scriptsSearched} scripts.*`,\n },\n ],\n };\n }\n\n const lines = result.results.map(\n (r) => `- \\`${r.scriptPath}:${r.lineNumber}\\`: ${r.line.trim()}`,\n );\n let text = lines.join(\"\\n\");\n if (result.totalMatches > result.results.length) {\n text += `\\n\\n*Showing ${result.results.length} of ${result.totalMatches} matches across ${result.scriptsSearched} scripts.*`;\n } else {\n text += `\\n\\n*${result.totalMatches} match(es) across ${result.scriptsSearched} scripts.*`;\n }\n\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n }\n\n // Default: instances\n const result = (await bridge.send(\"query_instances\", {\n basePath: params.basePath,\n filters: params.filters ?? {},\n limit: params.limit,\n })) as {\n results: Array<{ path: string; className: string; name: string }>;\n total: number;\n };\n\n let text: string;\n if (result.results.length === 0) {\n text = \"*No instances matched the query.*\";\n } else {\n const lines = result.results.map(\n (r) => `- \\`${r.path}\\` (${r.className})`,\n );\n text = lines.join(\"\\n\");\n if (result.total > result.results.length) {\n text += `\\n\\n*Showing ${result.results.length} of ${result.total} matches — increase limit or narrow filters.*`;\n }\n }\n\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n },\n );\n}\n\nfunction registerWrite(server: McpServer, bridge: Bridge): void {\n // ── create (merged create_instances + clone_instances) ────────────\n server.registerTool(\n \"create\",\n {\n title: \"Create or Clone Instances\",\n description:\n \"Create new instances or clone existing ones.\\n\\n\" +\n \"Actions:\\n\" +\n \"- `new` (default): Create instances with className, parent, name, and properties.\\n\" +\n \"- `clone`: Clone existing instances to a target parent.\",\n inputSchema: z.object({\n action: z\n .enum([\"new\", \"clone\"])\n .default(\"new\")\n .describe(\"Create mode\"),\n // For 'new' action\n operations: z\n .array(\n z.object({\n className: z.string().describe(\"Roblox class, e.g. 'Part'\"),\n parent: z.string().describe(\"Parent path, e.g. 'game.Workspace'\"),\n name: z.string().describe(\"Instance name\"),\n properties: z.record(z.unknown()).optional().describe(\"Initial properties\"),\n }),\n )\n .optional()\n .describe(\"Instances to create (for 'new' action)\"),\n // For 'clone' action\n sources: z\n .array(z.string())\n .optional()\n .describe(\"Paths of instances to clone (for 'clone' action)\"),\n targetParent: z\n .string()\n .optional()\n .describe(\"Parent to place clones under (for 'clone' action)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async (params) => {\n if (params.action === \"clone\") {\n if (!params.sources || params.sources.length === 0) {\n return { content: [{ type: \"text\", text: \"clone action requires a non-empty `sources` array.\" }] };\n }\n if (!params.targetParent) {\n return { content: [{ type: \"text\", text: \"clone action requires a `targetParent`.\" }] };\n }\n const result = (await bridge.send(\"clone_instances\", {\n sources: params.sources,\n targetParent: params.targetParent,\n })) as {\n cloned: Array<{ path: string; className: string; name: string }>;\n };\n const text = result.cloned\n .map((r) => `- \\`${r.path}\\` (${r.className})`)\n .join(\"\\n\");\n return { content: [{ type: \"text\", text }] };\n }\n\n // Default: new\n if (!params.operations || params.operations.length === 0) {\n return { content: [{ type: \"text\", text: \"new action requires a non-empty `operations` array.\" }] };\n }\n const result = (await bridge.send(\"create_instances\", {\n operations: params.operations,\n })) as {\n created: Array<{ path: string; className: string; name: string }>;\n };\n const text = result.created\n .map((r) => `- \\`${r.path}\\` (${r.className})`)\n .join(\"\\n\");\n return { content: [{ type: \"text\", text }] };\n },\n );\n\n // ── modify (merged modify_instances + batch_modify) ───────────────\n server.registerTool(\n \"modify\",\n {\n title: \"Modify Instances\",\n description:\n \"Modify existing instances.\\n\\n\" +\n \"Modes:\\n\" +\n \"- `targeted` (default): Per-instance modifications with properties, attributes, tags, name, parent.\\n\" +\n \"- `bulk`: Set one property to the same value across many instances.\",\n inputSchema: z.object({\n mode: z\n .enum([\"targeted\", \"bulk\"])\n .default(\"targeted\")\n .describe(\"Modification mode\"),\n // For 'targeted' mode\n operations: z\n .array(\n z.object({\n path: z.string().describe(\"Path to instance\"),\n properties: z.record(z.unknown()).optional().describe(\"Properties to set\"),\n attributes: z.record(z.unknown()).optional().describe(\"Attributes to set\"),\n tags: z\n .object({\n add: z.array(z.string()).optional().describe(\"Tags to add\"),\n remove: z.array(z.string()).optional().describe(\"Tags to remove\"),\n })\n .optional()\n .describe(\"Tag modifications\"),\n name: z.string().optional().describe(\"New name\"),\n parent: z.string().optional().describe(\"New parent path\"),\n }),\n )\n .optional()\n .describe(\"Per-instance modifications (for 'targeted' mode)\"),\n // For 'bulk' mode\n paths: z\n .array(z.string())\n .optional()\n .describe(\"Instance paths (for 'bulk' mode)\"),\n property: z\n .string()\n .optional()\n .describe(\"Property name (for 'bulk' mode)\"),\n value: z.unknown().optional().describe(\"Property value (for 'bulk' mode)\"),\n strict: z\n .boolean()\n .default(false)\n .describe(\"If true, any single failure rolls back the entire batch (for 'bulk' mode)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n if (params.mode === \"bulk\") {\n if (!params.paths || params.paths.length === 0) {\n return { content: [{ type: \"text\", text: \"bulk mode requires a non-empty `paths` array.\" }] };\n }\n if (!params.property) {\n return { content: [{ type: \"text\", text: \"bulk mode requires a `property` name.\" }] };\n }\n const result = (await bridge.send(\"batch_modify\", {\n paths: params.paths,\n property: params.property,\n value: params.value,\n strict: params.strict,\n })) as {\n modified: number;\n failed: Array<{ path: string; error: string }>;\n };\n\n let text = `Modified **${params.property}** on ${result.modified} instance(s).`;\n if (result.failed.length > 0) {\n text +=\n \"\\n\\nFailed:\\n\" +\n result.failed.map((f) => `- \\`${f.path}\\`: ${f.error}`).join(\"\\n\");\n }\n return { content: [{ type: \"text\", text }] };\n }\n\n // Default: targeted\n if (!params.operations || params.operations.length === 0) {\n return { content: [{ type: \"text\", text: \"targeted mode requires a non-empty `operations` array.\" }] };\n }\n const result = (await bridge.send(\"modify_instances\", {\n operations: params.operations,\n })) as {\n modified: Array<{ path: string; modified: string[] }>;\n };\n const text = result.modified\n .map((r) => `- \\`${r.path}\\` — modified: ${r.modified.join(\", \")}`)\n .join(\"\\n\");\n return { content: [{ type: \"text\", text }] };\n },\n );\n\n // ── delete ────────────────────────────────────────────────────────\n server.registerTool(\n \"delete\",\n {\n title: \"Delete Instances\",\n description:\n \"Permanently delete one or more instances by path. Destructive — use undo_redo to revert.\",\n inputSchema: z.object({\n paths: z\n .array(z.string())\n .describe(\"Paths of instances to delete\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n const result = (await bridge.send(\"delete_instances\", {\n paths: params.paths,\n })) as { deleted: string[] };\n const text = result.deleted\n .map((p) => `- \\`${p}\\` — deleted`)\n .join(\"\\n\");\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport { formatScript, applyTokenBudget } from \"../utils/formatting.js\";\n\nexport function registerReadOnly(server: McpServer, bridge: Bridge): void {\n registerReadScript(server, bridge);\n}\n\nexport function register(server: McpServer, bridge: Bridge): void {\n registerReadScript(server, bridge);\n registerWriteTools(server, bridge);\n}\n\nfunction registerReadScript(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"read_script\",\n {\n title: \"Read Script Source\",\n description:\n \"Read the Lua source code of a script instance. Optionally restrict to a line range.\",\n inputSchema: z.object({\n path: z.string().describe(\"Path to the script instance\"),\n lineRange: z\n .object({\n start: z.number().int().min(1).describe(\"Start line (1-based)\"),\n end: z.number().int().min(1).describe(\"End line (1-based, inclusive)\"),\n })\n .optional()\n .describe(\"Optional line range to read\"),\n maxTokens: z\n .number()\n .optional()\n .describe(\"Maximum token budget for the response\"),\n }),\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n const result = (await bridge.send(\"read_script\", {\n path: params.path,\n lineRange: params.lineRange,\n })) as { source: string };\n const text = formatScript(result.source, params.path);\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n },\n );\n}\n\nfunction registerWriteTools(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"edit_script\",\n {\n title: \"Edit Script Source\",\n description:\n \"Edit the Lua source code of a script. Supports four modes: 'full' replaces the entire source, 'range' replaces specific line/column ranges, 'find_replace' does text find-and-replace on one script, and 'multi_replace' does find-and-replace across multiple scripts in one undoable operation.\",\n inputSchema: z.object({\n path: z.string().describe(\"Path to the script instance\"),\n mode: z\n .enum([\"full\", \"range\", \"find_replace\", \"multi_replace\"])\n .describe(\"Edit mode: full, range, find_replace, or multi_replace\"),\n source: z\n .string()\n .optional()\n .describe(\"Complete new source (for 'full' mode)\"),\n edits: z\n .array(\n z.object({\n startLine: z.number().int().describe(\"Start line (1-based)\"),\n startColumn: z.number().int().describe(\"Start column (1-based)\"),\n endLine: z.number().int().describe(\"End line (1-based)\"),\n endColumn: z.number().int().describe(\"End column (1-based)\"),\n text: z.string().describe(\"Replacement text\"),\n }),\n )\n .optional()\n .describe(\"Range edits (for 'range' mode)\"),\n find: z\n .string()\n .optional()\n .describe(\"Text or pattern to find (for 'find_replace' mode)\"),\n replace: z\n .string()\n .optional()\n .describe(\"Replacement text (for 'find_replace' mode)\"),\n regex: z\n .boolean()\n .optional()\n .describe(\"Treat 'find' as a Lua pattern (for 'find_replace' and 'multi_replace' modes)\"),\n scripts: z\n .array(z.string())\n .optional()\n .describe(\"Array of script paths to apply find/replace across (for 'multi_replace' mode)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async (params) => {\n // ── multi_replace mode ────────────────────────────────────\n if (params.mode === \"multi_replace\") {\n if (!params.scripts || params.scripts.length === 0) {\n return { content: [{ type: \"text\", text: \"multi_replace mode requires a non-empty `scripts` array.\" }] };\n }\n if (!params.find) {\n return { content: [{ type: \"text\", text: \"multi_replace mode requires a `find` parameter.\" }] };\n }\n\n const result = (await bridge.send(\"multi_replace_scripts\", {\n scripts: params.scripts,\n find: params.find,\n replace: params.replace ?? \"\",\n regex: params.regex,\n })) as {\n results: Array<{ path: string; replacements: number }>;\n totalReplacements: number;\n scriptsModified: number;\n errors?: Array<{ path: string; error: string }>;\n };\n\n const lines: string[] = [\n `**Multi-script find/replace** — ${result.totalReplacements} replacements across ${result.scriptsModified} script(s)`,\n \"\",\n ];\n\n for (const r of result.results) {\n lines.push(`- \\`${r.path}\\`: ${r.replacements} replacement(s)`);\n }\n\n if (result.errors && result.errors.length > 0) {\n lines.push(\"\", \"**Errors:**\");\n for (const e of result.errors) {\n lines.push(`- \\`${e.path}\\`: ${e.error}`);\n }\n }\n\n return { content: [{ type: \"text\", text: lines.join(\"\\n\") }] };\n }\n\n const result = (await bridge.send(\"edit_script\", {\n path: params.path,\n mode: params.mode,\n source: params.source,\n edits: params.edits,\n find: params.find,\n replace: params.replace,\n regex: params.regex,\n })) as {\n path: string;\n mode: string;\n success: boolean;\n totalLines: number;\n appliedEdits?: number;\n replacements?: number;\n };\n let detail = `mode=${result.mode}, ${result.totalLines} total lines`;\n if (result.appliedEdits !== undefined) {\n detail += `, ${result.appliedEdits} edits applied`;\n }\n if (result.replacements !== undefined) {\n detail += `, ${result.replacements} replacements`;\n }\n const text = `Script **${params.path}** updated (${detail}).`;\n return { content: [{ type: \"text\", text }] };\n },\n );\n\n server.registerTool(\n \"execute_lua\",\n {\n title: \"Execute Luau Code\",\n description:\n \"Run arbitrary Luau code in the Studio plugin context (edit mode — no active playtest required). Use this as an escape hatch for any operation the other tools don't cover. Has access to all Studio APIs and services.\",\n inputSchema: z.object({\n code: z\n .string()\n .describe(\"Luau code to execute\"),\n maxTokens: z\n .number()\n .optional()\n .describe(\"Maximum token budget for the response\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async (params) => {\n const result = (await bridge.send(\"execute_lua\", {\n code: params.code,\n })) as {\n status: string;\n result?: string;\n error?: string;\n output?: Array<{ message: string; messageType: string }>;\n };\n\n const lines: string[] = [];\n if (result.error) {\n lines.push(`**Error:** ${result.error}`);\n }\n if (result.result) {\n lines.push(`**Return value:** ${result.result}`);\n }\n if (result.output && result.output.length > 0) {\n const outputText = result.output\n .map((o) => `[${o.messageType}] ${o.message}`)\n .join(\"\\n\");\n lines.push(`**Output:**\\n\\`\\`\\`\\n${outputText}\\n\\`\\`\\``);\n }\n\n const text =\n lines.length > 0\n ? lines.join(\"\\n\\n\")\n : `Execution completed (${result.status})`;\n\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport { applyTokenBudget } from \"../utils/formatting.js\";\n\nexport function register(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"playtest\",\n {\n title: \"Playtest Control & Virtual Input\",\n description:\n \"Control Roblox Studio playtesting and simulate user input.\\n\\n\" +\n \"Actions:\\n\" +\n \"- `start`: Begin a playtest session.\\n\" +\n \"- `stop`: End the current playtest.\\n\" +\n \"- `execute`: Run Lua code in the running game context.\\n\" +\n \"- `get_output`: Get console/log output from Studio (works in edit mode and during playtest).\\n\" +\n \"- `inspect`: Evaluate a Luau expression and return the typed result (requires active playtest).\\n\" +\n \"- `navigate`: Walk the player character to a position using PathfindingService (requires client playtest).\\n\" +\n \"- `mouse_click`: Simulate a mouse click at screen coordinates.\\n\" +\n \"- `mouse_move`: Move the virtual mouse to screen coordinates.\\n\" +\n \"- `key_press`: Press and release a key.\\n\" +\n \"- `key_down`: Hold a key down.\\n\" +\n \"- `key_up`: Release a held key.\",\n inputSchema: z.object({\n action: z\n .enum([\"start\", \"stop\", \"execute\", \"get_output\", \"inspect\", \"navigate\", \"mouse_click\", \"mouse_move\", \"key_press\", \"key_down\", \"key_up\"])\n .describe(\"Playtest action\"),\n code: z\n .string()\n .optional()\n .describe(\"Lua code to execute (for 'execute' action)\"),\n // get_output params\n messageTypes: z\n .array(z.string())\n .optional()\n .describe(\"Filter by message types: 'MessageOutput', 'MessageWarning', 'MessageError', 'MessageInfo' (for 'get_output')\"),\n since: z\n .number()\n .optional()\n .describe(\"Only return logs with timestamp >= this value (for 'get_output')\"),\n limit: z\n .number()\n .optional()\n .describe(\"Maximum number of log entries to return (for 'get_output')\"),\n // inspect params\n expression: z\n .string()\n .optional()\n .describe(\"Luau expression to evaluate, e.g. 'game.Players.Player1.Character.Humanoid.Health' (for 'inspect')\"),\n // navigate params\n target: z\n .object({\n x: z.number(),\n y: z.number(),\n z: z.number(),\n })\n .optional()\n .describe(\"Target position to navigate to (for 'navigate')\"),\n targetPath: z\n .string()\n .optional()\n .describe(\"Instance path to navigate to — uses its Position (for 'navigate')\"),\n timeout: z\n .number()\n .optional()\n .describe(\"Navigation timeout in seconds, default 15 (for 'navigate')\"),\n // Virtual input params\n x: z.number().optional().describe(\"Screen X coordinate (for mouse actions)\"),\n y: z.number().optional().describe(\"Screen Y coordinate (for mouse actions)\"),\n button: z\n .enum([\"Left\", \"Right\", \"Middle\"])\n .default(\"Left\")\n .describe(\"Mouse button (for 'mouse_click')\"),\n key: z\n .string()\n .optional()\n .describe(\"Key name matching Enum.KeyCode, e.g. 'W', 'Space', 'Return' (for key actions)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async (params) => {\n // ── get_output ──────────────────────────────────────────────\n if (params.action === \"get_output\") {\n const result = (await bridge.send(\"get_log_output\", {\n messageTypes: params.messageTypes,\n since: params.since,\n limit: params.limit,\n })) as {\n logs: Array<{ message: string; messageType: string; timestamp: number }>;\n total: number;\n };\n\n if (result.logs.length === 0) {\n return { content: [{ type: \"text\", text: \"No log output found.\" }] };\n }\n\n const header = `**Console Output** (${result.logs.length}${result.logs.length < result.total ? ` of ${result.total}` : \"\"} entries)`;\n const logText = result.logs\n .map((l) => `[${l.messageType}] ${l.message}`)\n .join(\"\\n\");\n const text = `${header}\\n\\n\\`\\`\\`\\n${logText}\\n\\`\\`\\``;\n\n return {\n content: [{ type: \"text\", text: applyTokenBudget(text, undefined) }],\n };\n }\n\n // ── inspect ─────────────────────────────────────────────────\n if (params.action === \"inspect\") {\n if (!params.expression) {\n return {\n content: [{ type: \"text\", text: \"inspect action requires an `expression` parameter.\" }],\n };\n }\n const result = (await bridge.send(\"playtest_inspect\", {\n expression: params.expression,\n })) as {\n value: unknown;\n type: string;\n expression: string;\n };\n\n const valueStr = typeof result.value === \"object\"\n ? JSON.stringify(result.value, null, 2)\n : String(result.value);\n const text = `**Expression:** \\`${result.expression}\\`\\n**Type:** \\`${result.type}\\`\\n**Value:** ${valueStr}`;\n return { content: [{ type: \"text\", text }] };\n }\n\n // ── navigate ────────────────────────────────────────────────\n if (params.action === \"navigate\") {\n if (!params.target && !params.targetPath) {\n return {\n content: [{ type: \"text\", text: \"navigate action requires either `target` or `targetPath`.\" }],\n };\n }\n const result = (await bridge.send(\"playtest_navigate\", {\n target: params.target,\n targetPath: params.targetPath,\n timeout: params.timeout,\n })) as {\n status: string;\n position?: { x: number; y: number; z: number };\n message?: string;\n };\n\n const posStr = result.position\n ? `(${result.position.x.toFixed(1)}, ${result.position.y.toFixed(1)}, ${result.position.z.toFixed(1)})`\n : \"unknown\";\n const text = `**Navigation:** ${result.status}\\n**Final position:** ${posStr}${result.message ? `\\n${result.message}` : \"\"}`;\n return { content: [{ type: \"text\", text }] };\n }\n\n // ── virtual input ───────────────────────────────────────────\n if (\n params.action === \"mouse_click\" ||\n params.action === \"mouse_move\" ||\n params.action === \"key_press\" ||\n params.action === \"key_down\" ||\n params.action === \"key_up\"\n ) {\n const result = (await bridge.send(\"virtual_input\", {\n action: params.action,\n x: params.x,\n y: params.y,\n button: params.button,\n key: params.key,\n })) as { status: string; message?: string };\n\n return {\n content: [\n { type: \"text\", text: result.message ?? `Virtual input ${params.action}: ${result.status}` },\n ],\n };\n }\n\n // Original playtest actions\n const result = (await bridge.send(\"playtest\", {\n action: params.action,\n code: params.code,\n })) as {\n status: string;\n result?: string;\n error?: string;\n output?: Array<{ message: string; messageType: string }>;\n };\n\n let text: string;\n if (params.action === \"execute\") {\n const lines: string[] = [];\n if (result.error) {\n lines.push(`**Error:** ${result.error}`);\n }\n if (result.result) {\n lines.push(`**Return value:** ${result.result}`);\n }\n if (result.output && result.output.length > 0) {\n const outputText = result.output\n .map((o) => `[${o.messageType}] ${o.message}`)\n .join(\"\\n\");\n lines.push(`**Output:**\\n\\`\\`\\`\\n${outputText}\\n\\`\\`\\``);\n }\n text =\n lines.length > 0\n ? lines.join(\"\\n\\n\")\n : `Execution completed (${result.status})`;\n text = applyTokenBudget(text, undefined);\n } else {\n text = `Playtest ${params.action}: ${result.status}`;\n }\n\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport { applyTokenBudget } from \"../utils/formatting.js\";\n\nconst Vector3Schema = z.object({\n X: z.number().describe(\"X coordinate\"),\n Y: z.number().describe(\"Y coordinate\"),\n Z: z.number().describe(\"Z coordinate\"),\n});\n\nconst RegionSchema = z.object({\n min: Vector3Schema.describe(\"Minimum corner of the region\"),\n max: Vector3Schema.describe(\"Maximum corner of the region\"),\n});\n\nexport function register(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"environment\",\n {\n title: \"Environment & Terrain\",\n description:\n \"Manage terrain and workspace/lighting settings.\\n\\n\" +\n \"Actions:\\n\" +\n \"- `terrain_fill`: Fill a region with a material.\\n\" +\n \"- `terrain_clear`: Clear terrain in a region (or all).\\n\" +\n \"- `terrain_read`: Read terrain data in a region.\\n\" +\n \"- `settings_get`: Get Workspace and Lighting properties.\\n\" +\n \"- `settings_set`: Set Workspace and Lighting properties.\",\n inputSchema: z.object({\n action: z\n .enum([\"terrain_fill\", \"terrain_clear\", \"terrain_read\", \"settings_get\", \"settings_set\"])\n .describe(\"Environment action\"),\n // Terrain params\n region: RegionSchema.optional().describe(\"Region for terrain operations\"),\n material: z\n .string()\n .optional()\n .describe(\"Terrain material name (for 'terrain_fill'), e.g. 'Grass'\"),\n size: Vector3Schema.optional().describe(\"Size override for terrain fill\"),\n // Settings params\n settings: z\n .record(z.unknown())\n .optional()\n .describe(\"Settings to set (for 'settings_set'). Keys: 'Workspace.Gravity', 'Lighting.ClockTime', etc.\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async (params) => {\n if (params.action === \"settings_get\") {\n const result = (await bridge.send(\"workspace_settings\", {\n action: \"get\",\n })) as { settings: Record<string, unknown> };\n\n const lines = [\"**Current Settings:**\", \"\"];\n for (const [k, v] of Object.entries(result.settings)) {\n lines.push(`- **${k}** = \\`${JSON.stringify(v)}\\``);\n }\n return { content: [{ type: \"text\", text: lines.join(\"\\n\") }] };\n }\n\n if (params.action === \"settings_set\") {\n if (!params.settings) {\n return { content: [{ type: \"text\", text: \"settings_set requires a `settings` object.\" }] };\n }\n const result = (await bridge.send(\"workspace_settings\", {\n action: \"set\",\n settings: params.settings,\n })) as { modified?: string[] };\n\n const text = `Updated ${result.modified?.length ?? 0} setting(s): ${result.modified?.join(\", \") ?? \"none\"}`;\n return { content: [{ type: \"text\", text }] };\n }\n\n // Terrain actions — map to the existing terrain command names\n const terrainAction = params.action.replace(\"terrain_\", \"\");\n const result = (await bridge.send(\"terrain\", {\n action: terrainAction,\n region: params.region,\n material: params.material,\n size: params.size,\n })) as {\n status?: string;\n material?: string;\n region?: unknown;\n resolution?: number;\n totalVoxels?: number;\n filledVoxels?: number;\n materials?: Record<string, number>;\n };\n\n let text: string;\n if (terrainAction === \"read\" && result.materials) {\n const data = {\n region: result.region,\n resolution: result.resolution,\n totalVoxels: result.totalVoxels,\n filledVoxels: result.filledVoxels,\n materials: result.materials,\n };\n text = `**Terrain data:**\\n\\`\\`\\`json\\n${JSON.stringify(data, null, 2)}\\n\\`\\`\\``;\n text = applyTokenBudget(text, undefined);\n } else {\n text = `Terrain ${terrainAction}: ${result.status}`;\n }\n\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport { applyTokenBudget } from \"../utils/formatting.js\";\n\nexport function register(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"assets\",\n {\n title: \"Asset Search & Insert\",\n description:\n \"Search the Roblox asset catalog or insert assets by ID.\\n\\n\" +\n \"Actions:\\n\" +\n \"- `search`: Search for models, meshes, images, audio.\\n\" +\n \"- `insert`: Insert an asset into the game by ID.\",\n inputSchema: z.object({\n action: z\n .enum([\"search\", \"insert\"])\n .describe(\"Asset action\"),\n // Search params\n query: z\n .string()\n .optional()\n .describe(\"Search query (for 'search' action)\"),\n category: z\n .string()\n .optional()\n .describe(\"Asset category: 'models', 'decals', 'images', etc. (for 'search')\"),\n maxResults: z\n .number()\n .int()\n .default(10)\n .describe(\"Max search results (for 'search')\"),\n // Insert params\n assetId: z\n .number()\n .int()\n .optional()\n .describe(\"Roblox asset ID (for 'insert' action)\"),\n parent: z\n .string()\n .optional()\n .describe(\"Parent path to insert under (for 'insert' action)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async (params) => {\n if (params.action === \"insert\") {\n if (!params.assetId) {\n return { content: [{ type: \"text\", text: \"insert action requires an `assetId`.\" }] };\n }\n if (!params.parent) {\n return { content: [{ type: \"text\", text: \"insert action requires a `parent` path.\" }] };\n }\n const result = (await bridge.send(\"insert_asset\", {\n assetId: params.assetId,\n parent: params.parent,\n })) as {\n assetId: number;\n inserted: Array<{ path: string; className: string; name: string }>;\n };\n const text =\n result.inserted.length === 1\n ? `Inserted asset **${params.assetId}** at \\`${result.inserted[0].path}\\``\n : `Inserted asset **${params.assetId}**:\\n` +\n result.inserted\n .map((i) => `- \\`${i.path}\\` (${i.className})`)\n .join(\"\\n\");\n return { content: [{ type: \"text\", text }] };\n }\n\n // Default: search\n if (!params.query) {\n return { content: [{ type: \"text\", text: \"search action requires a `query`.\" }] };\n }\n const result = (await bridge.send(\"search_assets\", {\n query: params.query,\n category: params.category,\n maxResults: params.maxResults,\n })) as {\n results: Array<{ assetId: number; name: string; creatorName: string }>;\n };\n\n let text: string;\n if (result.results.length === 0) {\n text = \"*No assets found matching your query.*\";\n } else {\n text = result.results\n .map((a) => `- **${a.name}** (ID: ${a.assetId}) by ${a.creatorName}`)\n .join(\"\\n\");\n }\n return {\n content: [{ type: \"text\", text: applyTokenBudget(text, undefined) }],\n };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport { applyTokenBudget } from \"../utils/formatting.js\";\nimport { searchApi, formatSearchResults } from \"../context/api-index.js\";\n\nexport function register(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"undo_redo\",\n {\n title: \"Undo / Redo\",\n description:\n \"Trigger undo or redo in Roblox Studio's change history. Supports repeating multiple times with the count parameter.\",\n inputSchema: z.object({\n action: z\n .enum([\"undo\", \"redo\"])\n .describe(\"Whether to undo or redo\"),\n count: z\n .number()\n .int()\n .min(1)\n .default(1)\n .describe(\"Number of times to repeat the action\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async (params) => {\n const result = (await bridge.send(\"undo_redo\", {\n action: params.action,\n count: params.count,\n })) as { status: string; count: number };\n const text = `${params.action === \"undo\" ? \"Undo\" : \"Redo\"} x${result.count}: ${result.status}`;\n return { content: [{ type: \"text\", text }] };\n },\n );\n\n server.registerTool(\n \"screenshot\",\n {\n title: \"Take Screenshot\",\n description:\n \"Capture a screenshot of the current Roblox Studio viewport. Returns base64 image data when available for vision model consumption.\",\n inputSchema: z.object({}),\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => {\n const result = (await bridge.send(\"screenshot\", {})) as {\n status: string;\n imageBase64?: string;\n mimeType?: string;\n message?: string;\n };\n\n if (result.imageBase64 && result.mimeType) {\n return {\n content: [\n {\n type: \"image\" as const,\n data: result.imageBase64,\n mimeType: result.mimeType,\n },\n ],\n };\n }\n\n return {\n content: [\n { type: \"text\", text: `Screenshot: ${result.message ?? result.status}` },\n ],\n };\n },\n );\n\n server.registerTool(\n \"lookup_api\",\n {\n title: \"Lookup Roblox API\",\n description:\n \"Search the Roblox engine API reference for classes, properties, methods, events, and enums. Runs locally — no Studio connection required.\",\n inputSchema: z.object({\n query: z\n .string()\n .describe(\"Search query, e.g. 'BasePart', 'Touched', 'TweenService'\"),\n maxTokens: z\n .number()\n .optional()\n .describe(\"Maximum token budget for the response\"),\n }),\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n const results = searchApi(params.query);\n const text = formatSearchResults(results);\n return {\n content: [\n { type: \"text\", text: applyTokenBudget(text, params.maxTokens) },\n ],\n };\n },\n );\n\n server.registerTool(\n \"transaction\",\n {\n title: \"Transaction Control\",\n description:\n \"Group multiple mutating tool calls into a single Ctrl+Z undo point.\\n\\n\" +\n \"Actions:\\n\" +\n \"- `begin`: Start a transaction. All subsequent writes share one undo recording.\\n\" +\n \"- `commit`: Finish the transaction and commit all changes as one undo point.\\n\" +\n \"- `rollback`: Cancel the transaction and undo all changes made since begin.\\n\\n\" +\n \"Transactions auto-rollback after 60 seconds if not committed.\",\n inputSchema: z.object({\n action: z\n .enum([\"begin\", \"commit\", \"rollback\"])\n .describe(\"Transaction action\"),\n name: z\n .string()\n .optional()\n .describe(\"Transaction name for the undo history (for 'begin' action)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async (params) => {\n if (params.action === \"begin\") {\n const result = (await bridge.send(\"begin_transaction\", {\n name: params.name,\n })) as { transactionId: string; status: string };\n return {\n content: [\n { type: \"text\", text: `Transaction started: **${result.transactionId}**\\nAll subsequent writes will be grouped into one undo point. Call commit or rollback to finish.` },\n ],\n };\n }\n\n if (params.action === \"commit\") {\n const result = (await bridge.send(\"commit_transaction\", {})) as {\n status: string;\n };\n return {\n content: [\n { type: \"text\", text: `Transaction ${result.status}. All changes are now a single undo point.` },\n ],\n };\n }\n\n // rollback\n const result = (await bridge.send(\"rollback_transaction\", {})) as {\n status: string;\n };\n return {\n content: [\n { type: \"text\", text: `Transaction ${result.status}. All changes since begin have been reverted.` },\n ],\n };\n },\n );\n}\n","{\n \"classes\": [\n {\n \"name\": \"Instance\",\n \"properties\": [\n {\"name\": \"Name\", \"type\": \"string\"},\n {\"name\": \"ClassName\", \"type\": \"string\", \"tags\": [\"ReadOnly\"]},\n {\"name\": \"Parent\", \"type\": \"Instance?\"}\n ],\n \"methods\": [\n {\"name\": \"FindFirstChild\", \"parameters\": [{\"name\": \"name\", \"type\": \"string\"}, {\"name\": \"recursive\", \"type\": \"boolean?\"}], \"returnType\": \"Instance?\"},\n {\"name\": \"GetChildren\", \"parameters\": [], \"returnType\": \"{Instance}\"},\n {\"name\": \"GetDescendants\", \"parameters\": [], \"returnType\": \"{Instance}\"},\n {\"name\": \"Destroy\", \"parameters\": [], \"returnType\": \"void\"},\n {\"name\": \"Clone\", \"parameters\": [], \"returnType\": \"Instance\"},\n {\"name\": \"IsA\", \"parameters\": [{\"name\": \"className\", \"type\": \"string\"}], \"returnType\": \"boolean\"},\n {\"name\": \"SetAttribute\", \"parameters\": [{\"name\": \"name\", \"type\": \"string\"}, {\"name\": \"value\", \"type\": \"any\"}], \"returnType\": \"void\"},\n {\"name\": \"GetAttribute\", \"parameters\": [{\"name\": \"name\", \"type\": \"string\"}], \"returnType\": \"any\"},\n {\"name\": \"GetAttributes\", \"parameters\": [], \"returnType\": \"{[string]: any}\"}\n ],\n \"events\": [\n {\"name\": \"ChildAdded\"},\n {\"name\": \"ChildRemoved\"},\n {\"name\": \"Changed\"}\n ]\n },\n {\n \"name\": \"BasePart\",\n \"superclass\": \"PVInstance\",\n \"properties\": [\n {\"name\": \"Position\", \"type\": \"Vector3\"},\n {\"name\": \"Size\", \"type\": \"Vector3\"},\n {\"name\": \"CFrame\", \"type\": \"CFrame\"},\n {\"name\": \"Color\", \"type\": \"Color3\"},\n {\"name\": \"BrickColor\", \"type\": \"BrickColor\"},\n {\"name\": \"Material\", \"type\": \"Enum.Material\"},\n {\"name\": \"Transparency\", \"type\": \"number\"},\n {\"name\": \"Anchored\", \"type\": \"boolean\"},\n {\"name\": \"CanCollide\", \"type\": \"boolean\"},\n {\"name\": \"Massless\", \"type\": \"boolean\"}\n ],\n \"methods\": [],\n \"events\": [{\"name\": \"Touched\"}]\n },\n {\n \"name\": \"Part\",\n \"superclass\": \"BasePart\",\n \"properties\": [\n {\"name\": \"Shape\", \"type\": \"Enum.PartType\"}\n ],\n \"methods\": [],\n \"events\": []\n },\n {\n \"name\": \"Model\",\n \"superclass\": \"PVInstance\",\n \"properties\": [\n {\"name\": \"PrimaryPart\", \"type\": \"BasePart?\"}\n ],\n \"methods\": [\n {\"name\": \"GetBoundingBox\", \"parameters\": [], \"returnType\": \"(CFrame, Vector3)\"},\n {\"name\": \"MoveTo\", \"parameters\": [{\"name\": \"position\", \"type\": \"Vector3\"}], \"returnType\": \"void\"}\n ],\n \"events\": []\n },\n {\n \"name\": \"Workspace\",\n \"superclass\": \"WorldRoot\",\n \"properties\": [\n {\"name\": \"CurrentCamera\", \"type\": \"Camera?\"},\n {\"name\": \"Gravity\", \"type\": \"number\"},\n {\"name\": \"Terrain\", \"type\": \"Terrain\"}\n ],\n \"methods\": [\n {\"name\": \"Raycast\", \"parameters\": [{\"name\": \"origin\", \"type\": \"Vector3\"}, {\"name\": \"direction\", \"type\": \"Vector3\"}, {\"name\": \"raycastParams\", \"type\": \"RaycastParams?\"}], \"returnType\": \"RaycastResult?\"}\n ],\n \"events\": []\n },\n {\n \"name\": \"Script\",\n \"superclass\": \"BaseScript\",\n \"properties\": [\n {\"name\": \"Source\", \"type\": \"string\"}\n ],\n \"methods\": [],\n \"events\": []\n },\n {\n \"name\": \"LocalScript\",\n \"superclass\": \"BaseScript\",\n \"properties\": [\n {\"name\": \"Source\", \"type\": \"string\"}\n ],\n \"methods\": [],\n \"events\": []\n },\n {\n \"name\": \"ModuleScript\",\n \"superclass\": \"LuaSourceContainer\",\n \"properties\": [\n {\"name\": \"Source\", \"type\": \"string\"}\n ],\n \"methods\": [],\n \"events\": []\n }\n ],\n \"enums\": [\n {\n \"name\": \"Material\",\n \"items\": [\n {\"name\": \"Plastic\", \"value\": 256},\n {\"name\": \"Wood\", \"value\": 512},\n {\"name\": \"Slate\", \"value\": 800},\n {\"name\": \"Concrete\", \"value\": 816},\n {\"name\": \"CorrodedMetal\", \"value\": 1040},\n {\"name\": \"DiamondPlate\", \"value\": 1056},\n {\"name\": \"Foil\", \"value\": 1072},\n {\"name\": \"Grass\", \"value\": 1280},\n {\"name\": \"Ice\", \"value\": 1536},\n {\"name\": \"Marble\", \"value\": 784},\n {\"name\": \"Granite\", \"value\": 832},\n {\"name\": \"Brick\", \"value\": 848},\n {\"name\": \"Pebble\", \"value\": 864},\n {\"name\": \"Sand\", \"value\": 1296},\n {\"name\": \"Fabric\", \"value\": 1312},\n {\"name\": \"SmoothPlastic\", \"value\": 272},\n {\"name\": \"Metal\", \"value\": 1024},\n {\"name\": \"WoodPlanks\", \"value\": 528},\n {\"name\": \"Neon\", \"value\": 288},\n {\"name\": \"Glass\", \"value\": 1568}\n ]\n },\n {\n \"name\": \"PartType\",\n \"items\": [\n {\"name\": \"Ball\", \"value\": 0},\n {\"name\": \"Block\", \"value\": 1},\n {\"name\": \"Cylinder\", \"value\": 2}\n ]\n }\n ]\n}\n","import rawApiData from \"./api-data.json\";\n\ninterface ApiClass {\n name: string;\n superclass?: string;\n properties: ApiMember[];\n methods: ApiMember[];\n events: ApiMember[];\n}\n\ninterface ApiMember {\n name: string;\n type?: string;\n parameters?: Array<{ name: string; type: string }>;\n returnType?: string;\n description?: string;\n tags?: string[];\n}\n\ninterface ApiEnum {\n name: string;\n items: Array<{ name: string; value: number }>;\n}\n\ninterface ApiData {\n classes: ApiClass[];\n enums: ApiEnum[];\n}\n\nconst apiData: ApiData = rawApiData as ApiData;\n\nexport interface SearchResult {\n type: \"class\" | \"property\" | \"method\" | \"event\" | \"enum\";\n className?: string;\n name: string;\n detail: string;\n}\n\nexport function searchApi(query: string, maxResults: number = 20): SearchResult[] {\n const data = apiData;\n const q = query.toLowerCase();\n const results: SearchResult[] = [];\n\n for (const cls of data.classes) {\n if (cls.name.toLowerCase().includes(q)) {\n const props = cls.properties.map((p) => p.name).join(\", \");\n const methods = cls.methods.map((m) => m.name).join(\", \");\n results.push({\n type: \"class\",\n name: cls.name,\n detail: `Inherits: ${cls.superclass ?? \"none\"}\\nProperties: ${props || \"none\"}\\nMethods: ${methods || \"none\"}`,\n });\n }\n\n for (const prop of cls.properties) {\n if (prop.name.toLowerCase().includes(q)) {\n results.push({\n type: \"property\",\n className: cls.name,\n name: prop.name,\n detail: `${cls.name}.${prop.name}: ${prop.type ?? \"unknown\"}${prop.tags?.length ? ` [${prop.tags.join(\", \")}]` : \"\"}`,\n });\n }\n }\n\n for (const method of cls.methods) {\n if (method.name.toLowerCase().includes(q)) {\n const params = method.parameters\n ?.map((p) => `${p.name}: ${p.type}`)\n .join(\", \") ?? \"\";\n results.push({\n type: \"method\",\n className: cls.name,\n name: method.name,\n detail: `${cls.name}:${method.name}(${params}): ${method.returnType ?? \"void\"}`,\n });\n }\n }\n\n for (const event of cls.events) {\n if (event.name.toLowerCase().includes(q)) {\n results.push({\n type: \"event\",\n className: cls.name,\n name: event.name,\n detail: `${cls.name}.${event.name}`,\n });\n }\n }\n\n if (results.length >= maxResults * 3) break; // early exit for large datasets\n }\n\n for (const en of data.enums) {\n if (en.name.toLowerCase().includes(q)) {\n const items = en.items.map((i) => i.name).join(\", \");\n results.push({\n type: \"enum\",\n name: en.name,\n detail: `Enum.${en.name}: ${items}`,\n });\n }\n }\n\n // Sort: exact matches first, then by name length\n results.sort((a, b) => {\n const aExact = a.name.toLowerCase() === q ? 0 : 1;\n const bExact = b.name.toLowerCase() === q ? 0 : 1;\n if (aExact !== bExact) return aExact - bExact;\n return a.name.length - b.name.length;\n });\n\n return results.slice(0, maxResults);\n}\n\nexport function formatSearchResults(results: SearchResult[]): string {\n if (results.length === 0) {\n return \"*No results found. Try a different search term.*\";\n }\n\n const lines: string[] = [];\n for (const r of results) {\n const prefix = r.type.charAt(0).toUpperCase() + r.type.slice(1);\n lines.push(`### ${prefix}: ${r.name}`);\n lines.push(r.detail);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\n\nexport function register(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"list_studios\",\n {\n title: \"List Connected Studios\",\n description:\n \"List all Roblox Studio instances currently connected to Conduit. Shows studio ID, place name, place ID, and which studio is active. Use set_active_studio to switch between them.\",\n inputSchema: z.object({}),\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => {\n const studios = bridge.getStudios();\n const activeId = bridge.getActiveStudioId();\n\n if (studios.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"*No Roblox Studio instances connected.* Make sure the Conduit plugin is installed and running.\",\n },\n ],\n };\n }\n\n const lines = studios.map((s) => {\n const active = s.studioId === activeId ? \" **← active**\" : \"\";\n const place = s.placeName ? ` — ${s.placeName}` : \"\";\n const placeId = s.placeId ? ` (Place ID: ${s.placeId})` : \"\";\n const duration = Math.floor((Date.now() - s.connectedAt) / 1000);\n return `- \\`${s.studioId}\\`${place}${placeId} — connected ${duration}s ago${active}`;\n });\n\n const text = `**Connected Studios (${studios.length}):**\\n${lines.join(\"\\n\")}`;\n return { content: [{ type: \"text\", text }] };\n },\n );\n\n server.registerTool(\n \"set_active_studio\",\n {\n title: \"Set Active Studio\",\n description:\n \"Switch which Roblox Studio instance receives tool commands. Use list_studios to see available IDs.\",\n inputSchema: z.object({\n studioId: z\n .string()\n .describe(\"The studio ID to set as active (from list_studios)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (params) => {\n bridge.setActiveStudio(params.studioId);\n const studios = bridge.getStudios();\n const studio = studios.find((s) => s.studioId === params.studioId);\n const name = studio?.placeName ?? \"unknown\";\n const text = `Active studio set to \\`${params.studioId}\\` (${name}).`;\n return { content: [{ type: \"text\", text }] };\n },\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\nimport { saveBuild, loadBuild, listBuilds } from \"../utils/builds.js\";\n\nexport function register(server: McpServer, bridge: Bridge): void {\n server.registerTool(\n \"builds\",\n {\n title: \"Build Library\",\n description:\n \"Export, import, or list reusable instance trees (build library).\\n\\n\" +\n \"Actions:\\n\" +\n \"- `export`: Serialize an instance tree and save it as a named build.\\n\" +\n \"- `import`: Reconstruct a saved build under a target parent.\\n\" +\n \"- `list`: List all saved builds.\",\n inputSchema: z.object({\n action: z\n .enum([\"export\", \"import\", \"list\"])\n .describe(\"Build library action\"),\n // Export params\n path: z\n .string()\n .optional()\n .describe(\"Path to instance to export (for 'export' action)\"),\n name: z\n .string()\n .optional()\n .describe(\"Build name (for 'export' and 'import' actions)\"),\n description: z\n .string()\n .optional()\n .describe(\"Build description (for 'export' action)\"),\n // Import params\n targetParent: z\n .string()\n .optional()\n .describe(\"Parent path to import under (for 'import' action)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async (params) => {\n if (params.action === \"list\") {\n const builds = listBuilds();\n if (builds.length === 0) {\n return {\n content: [\n { type: \"text\", text: \"*No builds saved. Use `builds --action export` to save one.*\" },\n ],\n };\n }\n const lines = builds.map(\n (b) =>\n `- **${b.name}** \\`${b.rootClassName}\\` (${b.childCount} children) — ${b.createdAt}${b.description ? `\\n ${b.description}` : \"\"}`,\n );\n return {\n content: [{ type: \"text\", text: lines.join(\"\\n\") }],\n };\n }\n\n if (params.action === \"export\") {\n if (!params.path) {\n return { content: [{ type: \"text\", text: \"export action requires a `path`.\" }] };\n }\n if (!params.name) {\n return { content: [{ type: \"text\", text: \"export action requires a `name`.\" }] };\n }\n\n // Ask plugin to serialize the instance tree\n const serialized = await bridge.send(\"export_build\", {\n path: params.path,\n });\n\n const meta = saveBuild(params.name, serialized, params.description);\n return {\n content: [\n {\n type: \"text\",\n text: `Build **${meta.name}** saved.\\n- Root: \\`${meta.rootClassName}\\`\\n- Children: ${meta.childCount}\\n- Created: ${meta.createdAt}`,\n },\n ],\n };\n }\n\n if (params.action === \"import\") {\n if (!params.name) {\n return { content: [{ type: \"text\", text: \"import action requires a `name`.\" }] };\n }\n if (!params.targetParent) {\n return { content: [{ type: \"text\", text: \"import action requires a `targetParent`.\" }] };\n }\n\n const build = loadBuild(params.name);\n\n const result = (await bridge.send(\"import_build\", {\n tree: build.root,\n targetParent: params.targetParent,\n })) as { path: string; className: string; childCount: number };\n\n return {\n content: [\n {\n type: \"text\",\n text: `Build **${params.name}** imported at \\`${result.path}\\` (${result.className}, ${result.childCount} children).`,\n },\n ],\n };\n }\n\n return { content: [{ type: \"text\", text: \"Unknown builds action.\" }] };\n },\n );\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\n\nconst BUILDS_DIR = join(homedir(), \".conduit\", \"builds\");\n\nfunction ensureDir(): void {\n if (!existsSync(BUILDS_DIR)) {\n mkdirSync(BUILDS_DIR, { recursive: true });\n }\n}\n\nexport interface BuildMetadata {\n name: string;\n description?: string;\n createdAt: string;\n rootClassName: string;\n childCount: number;\n}\n\nexport interface BuildFile {\n name: string;\n description?: string;\n createdAt: string;\n root: unknown;\n}\n\nexport function saveBuild(\n name: string,\n root: unknown,\n description?: string,\n): BuildMetadata {\n ensureDir();\n const rootObj = root as { className?: string; children?: unknown[] };\n const data: BuildFile = {\n name,\n description,\n createdAt: new Date().toISOString(),\n root,\n };\n const filePath = join(BUILDS_DIR, `${name}.json`);\n writeFileSync(filePath, JSON.stringify(data, null, 2), \"utf-8\");\n return {\n name,\n description,\n createdAt: data.createdAt,\n rootClassName: rootObj.className ?? \"unknown\",\n childCount: rootObj.children?.length ?? 0,\n };\n}\n\nexport function loadBuild(name: string): BuildFile {\n const filePath = join(BUILDS_DIR, `${name}.json`);\n if (!existsSync(filePath)) {\n throw new Error(`Build \"${name}\" not found. Use builds --action list to see available builds.`);\n }\n return JSON.parse(readFileSync(filePath, \"utf-8\")) as BuildFile;\n}\n\nexport function listBuilds(): BuildMetadata[] {\n ensureDir();\n const files = readdirSync(BUILDS_DIR).filter((f) => f.endsWith(\".json\"));\n return files.map((f) => {\n const filePath = join(BUILDS_DIR, f);\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\")) as BuildFile;\n const rootObj = data.root as { className?: string; children?: unknown[] };\n return {\n name: data.name,\n description: data.description,\n createdAt: data.createdAt,\n rootClassName: rootObj.className ?? \"unknown\",\n childCount: rootObj.children?.length ?? 0,\n };\n } catch {\n const stat = statSync(filePath);\n return {\n name: f.replace(\".json\", \"\"),\n createdAt: stat.mtime.toISOString(),\n rootClassName: \"unknown\",\n childCount: 0,\n };\n }\n });\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Bridge } from \"../bridge.js\";\n\nimport { register as registerExplore } from \"./explore.js\";\nimport { register as registerInstances, registerReadOnly as registerInstancesReadOnly } from \"./instances.js\";\nimport { register as registerScripts, registerReadOnly as registerScriptsReadOnly } from \"./scripts.js\";\nimport { register as registerPlaytest } from \"./playtest.js\";\nimport { register as registerEnvironment } from \"./environment.js\";\nimport { register as registerAssets } from \"./assets.js\";\nimport { register as registerUtility } from \"./utility.js\";\nimport { register as registerStudio } from \"./studio.js\";\nimport { register as registerBuilds } from \"./builds.js\";\n\nexport interface ToolRegistrationOptions {\n mode?: \"full\" | \"inspector\";\n withCloud?: boolean;\n withRojo?: boolean;\n}\n\nexport function registerAllTools(\n server: McpServer,\n bridge: Bridge,\n options: ToolRegistrationOptions = {},\n): void {\n const mode = options.mode ?? \"full\";\n\n // Read-only tools — always registered\n registerStudio(server, bridge);\n registerExplore(server, bridge);\n registerUtility(server, bridge);\n\n if (mode === \"full\") {\n // Write tools — only in full mode\n registerInstances(server, bridge);\n registerScripts(server, bridge);\n registerPlaytest(server, bridge);\n registerEnvironment(server, bridge);\n registerAssets(server, bridge);\n registerBuilds(server, bridge);\n } else {\n // Inspector mode — only read-only tools (query, read_script)\n registerInstancesReadOnly(server, bridge);\n registerScriptsReadOnly(server, bridge);\n }\n\n // Optional modules (loaded dynamically to avoid bundling when unused)\n if (options.withCloud) {\n import(\"../modules/cloud.js\").then((mod) => mod.register(server));\n }\n if (options.withRojo) {\n import(\"../modules/rojo.js\").then((mod) => mod.register(server));\n }\n}\n"],"mappings":"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","names":["waiters","result","text","z","register","z","result","text","z","registerReadOnly","register","z","result","z","register","z","result","text","z","z","register","result","text","z","register","z","result","text","z","register","z","result","z","register","z","register","z","register","registerReadOnly"]}
package/dist/cli.js ADDED
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ startServer
4
+ } from "./chunk-JDWBW44K.js";
5
+
6
+ // src/cli.ts
7
+ import { parseArgs } from "util";
8
+ import { homedir, platform } from "os";
9
+ import { join } from "path";
10
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
11
+ import { dirname } from "path";
12
+ import { fileURLToPath } from "url";
13
+ var __dirname = dirname(fileURLToPath(import.meta.url));
14
+ var { values } = parseArgs({
15
+ options: {
16
+ install: { type: "boolean", default: false },
17
+ "auto-config": { type: "boolean", default: false },
18
+ port: { type: "string", default: "3200" },
19
+ mode: { type: "string", default: "full" },
20
+ "with-cloud": { type: "boolean", default: false },
21
+ "with-rojo": { type: "boolean", default: false },
22
+ version: { type: "boolean", default: false },
23
+ help: { type: "boolean", default: false }
24
+ },
25
+ strict: false
26
+ });
27
+ if (values.version) {
28
+ const pkg = JSON.parse(
29
+ readFileSync(join(__dirname, "..", "package.json"), "utf-8")
30
+ );
31
+ console.log(`conduit-mcp v${pkg.version}`);
32
+ process.exit(0);
33
+ }
34
+ if (values.help) {
35
+ console.log(`
36
+ conduit-mcp \u2014 WebSocket-first MCP bridge for Roblox Studio
37
+
38
+ Usage:
39
+ npx conduit-mcp Start the MCP server (stdio transport)
40
+ npx conduit-mcp --install Install the Studio plugin & show config
41
+ npx conduit-mcp --version Print version
42
+
43
+ Options:
44
+ --install Install the Conduit plugin to Roblox Studio
45
+ --auto-config Also write config to detected AI clients
46
+ --port <number> Override default bridge port (default: 3200)
47
+ --mode <mode> Tool mode: 'full' (default) or 'inspector' (read-only tools only)
48
+ --with-cloud Enable Cloud module (requires ROBLOX_CLOUD_API_KEY env var)
49
+ --with-rojo Enable Rojo module (requires rojo on PATH)
50
+ --help Show this help message
51
+ `);
52
+ process.exit(0);
53
+ }
54
+ if (values.install) {
55
+ await install(values["auto-config"]);
56
+ process.exit(0);
57
+ }
58
+ var mode = values.mode || "full";
59
+ if (mode !== "full" && mode !== "inspector") {
60
+ console.error(`Unknown mode: ${mode}. Expected 'full' or 'inspector'.`);
61
+ process.exit(1);
62
+ }
63
+ var port = parseInt(values.port) || 3200;
64
+ await startServer(port, {
65
+ mode,
66
+ withCloud: values["with-cloud"],
67
+ withRojo: values["with-rojo"]
68
+ });
69
+ async function install(autoConfig) {
70
+ console.log("Conduit MCP \u2014 Installation\n");
71
+ const pluginInstalled = installPlugin();
72
+ const clients = detectClients();
73
+ if (clients.length === 0) {
74
+ console.log("No AI clients detected. Add this to your client's MCP config:\n");
75
+ printConfigSnippet();
76
+ } else {
77
+ console.log(`
78
+ Detected AI clients: ${clients.map((c) => c.name).join(", ")}
79
+ `);
80
+ for (const client of clients) {
81
+ if (autoConfig) {
82
+ writeClientConfig(client);
83
+ } else {
84
+ console.log(`${client.name} \u2014 add this to ${client.configPath}:
85
+ `);
86
+ printConfigSnippet();
87
+ }
88
+ }
89
+ }
90
+ console.log(pluginInstalled ? "\nInstallation complete!" : "\nPlugin installation failed \u2014 install manually from GitHub releases.");
91
+ console.log("\nNext steps:");
92
+ console.log(" 1. Open Roblox Studio");
93
+ console.log(" 2. Enable HttpService (Game Settings > Security > Allow HTTP Requests)");
94
+ console.log(" 3. The Conduit plugin will auto-connect when the MCP server starts");
95
+ }
96
+ function installPlugin() {
97
+ const pluginSrc = join(__dirname, "..", "plugin", "Conduit.rbxm");
98
+ if (!existsSync(pluginSrc)) {
99
+ console.log("Plugin file not found at: " + pluginSrc);
100
+ return false;
101
+ }
102
+ const pluginsDir = getPluginsDir();
103
+ if (!pluginsDir) {
104
+ console.log("Could not determine Roblox Studio plugins directory for this platform.");
105
+ return false;
106
+ }
107
+ if (!existsSync(pluginsDir)) {
108
+ mkdirSync(pluginsDir, { recursive: true });
109
+ }
110
+ const dest = join(pluginsDir, "Conduit.rbxm");
111
+ copyFileSync(pluginSrc, dest);
112
+ console.log(`Plugin installed to: ${dest}`);
113
+ return true;
114
+ }
115
+ function getPluginsDir() {
116
+ const os = platform();
117
+ if (os === "win32") {
118
+ const localAppData = process.env.LOCALAPPDATA;
119
+ if (localAppData) {
120
+ return join(localAppData, "Roblox", "Plugins");
121
+ }
122
+ return join(homedir(), "AppData", "Local", "Roblox", "Plugins");
123
+ }
124
+ if (os === "darwin") {
125
+ return join(homedir(), "Documents", "Roblox", "Plugins");
126
+ }
127
+ return null;
128
+ }
129
+ function detectClients() {
130
+ const home = homedir();
131
+ const candidates = [
132
+ {
133
+ name: "Claude Code",
134
+ configPath: join(home, ".claude", "settings.json"),
135
+ configKey: "mcpServers"
136
+ },
137
+ {
138
+ name: "Cursor",
139
+ configPath: join(home, ".cursor", "mcp.json"),
140
+ configKey: "mcpServers"
141
+ },
142
+ {
143
+ name: "Windsurf",
144
+ configPath: join(home, ".windsurf", "mcp.json"),
145
+ configKey: "mcpServers"
146
+ },
147
+ {
148
+ name: "Claude Desktop (Windows)",
149
+ configPath: join(
150
+ process.env.APPDATA || join(home, "AppData", "Roaming"),
151
+ "Claude",
152
+ "claude_desktop_config.json"
153
+ ),
154
+ configKey: "mcpServers"
155
+ },
156
+ {
157
+ name: "Claude Desktop (macOS)",
158
+ configPath: join(
159
+ home,
160
+ "Library",
161
+ "Application Support",
162
+ "Claude",
163
+ "claude_desktop_config.json"
164
+ ),
165
+ configKey: "mcpServers"
166
+ }
167
+ ];
168
+ return candidates.filter((c) => {
169
+ try {
170
+ return existsSync(dirname(c.configPath));
171
+ } catch {
172
+ return false;
173
+ }
174
+ });
175
+ }
176
+ function printConfigSnippet() {
177
+ const snippet = {
178
+ conduit: {
179
+ command: "npx",
180
+ args: ["-y", "conduit-mcp"]
181
+ }
182
+ };
183
+ console.log(JSON.stringify(snippet, null, 2));
184
+ }
185
+ function writeClientConfig(client) {
186
+ try {
187
+ let config = {};
188
+ if (existsSync(client.configPath)) {
189
+ config = JSON.parse(readFileSync(client.configPath, "utf-8"));
190
+ }
191
+ const servers = config[client.configKey] ?? {};
192
+ servers["conduit"] = {
193
+ command: "npx",
194
+ args: ["-y", "conduit-mcp"]
195
+ };
196
+ config[client.configKey] = servers;
197
+ const dir = dirname(client.configPath);
198
+ if (!existsSync(dir)) {
199
+ mkdirSync(dir, { recursive: true });
200
+ }
201
+ writeFileSync(client.configPath, JSON.stringify(config, null, 2) + "\n");
202
+ console.log(`${client.name} \u2014 config written to ${client.configPath}`);
203
+ } catch (err) {
204
+ console.log(`${client.name} \u2014 failed to write config: ${err}`);
205
+ }
206
+ }
207
+ //# sourceMappingURL=cli.js.map