luca 2.0.0 → 3.0.2
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.
- package/.github/workflows/release.yaml +170 -0
- package/AGENTS.md +99 -0
- package/CLAUDE.md +123 -0
- package/CNAME +1 -0
- package/README.md +275 -9
- package/RUNME.md +56 -0
- package/assistants/codingAssistant/ABOUT.md +5 -0
- package/assistants/codingAssistant/CORE.md +33 -0
- package/assistants/codingAssistant/hooks.ts +21 -0
- package/assistants/codingAssistant/tools.ts +12 -0
- package/assistants/inkbot/ABOUT.md +16 -0
- package/assistants/inkbot/CORE.md +330 -0
- package/assistants/inkbot/hooks.ts +6 -0
- package/assistants/inkbot/tools.ts +53 -0
- package/assistants/researcher/ABOUT.md +5 -0
- package/assistants/researcher/CORE.md +46 -0
- package/assistants/researcher/hooks.ts +16 -0
- package/assistants/researcher/tools.ts +237 -0
- package/bun.lock +2667 -0
- package/bunfig.toml +3 -0
- package/commands/audit-docs.ts +740 -0
- package/commands/build-bootstrap.ts +117 -0
- package/commands/build-python-bridge.ts +42 -0
- package/commands/build-scaffolds.ts +175 -0
- package/commands/bundle-consumer-project.ts +521 -0
- package/commands/generate-api-docs.ts +114 -0
- package/commands/inkbot.ts +874 -0
- package/commands/release.ts +80 -0
- package/commands/try-all-challenges.ts +543 -0
- package/commands/try-challenge.ts +100 -0
- package/dist/agi/container.server.d.ts +63 -0
- package/dist/agi/container.server.d.ts.map +1 -0
- package/dist/agi/endpoints/ask.d.ts +20 -0
- package/dist/agi/endpoints/ask.d.ts.map +1 -0
- package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
- package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
- package/dist/agi/endpoints/conversations.d.ts +18 -0
- package/dist/agi/endpoints/conversations.d.ts.map +1 -0
- package/dist/agi/endpoints/experts.d.ts +8 -0
- package/dist/agi/endpoints/experts.d.ts.map +1 -0
- package/dist/agi/feature.d.ts +9 -0
- package/dist/agi/feature.d.ts.map +1 -0
- package/dist/agi/features/assistant.d.ts +509 -0
- package/dist/agi/features/assistant.d.ts.map +1 -0
- package/dist/agi/features/assistants-manager.d.ts +236 -0
- package/dist/agi/features/assistants-manager.d.ts.map +1 -0
- package/dist/agi/features/autonomous-assistant.d.ts +281 -0
- package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
- package/dist/agi/features/browser-use.d.ts +479 -0
- package/dist/agi/features/browser-use.d.ts.map +1 -0
- package/dist/agi/features/claude-code.d.ts +824 -0
- package/dist/agi/features/claude-code.d.ts.map +1 -0
- package/dist/agi/features/conversation-history.d.ts +245 -0
- package/dist/agi/features/conversation-history.d.ts.map +1 -0
- package/dist/agi/features/conversation.d.ts +464 -0
- package/dist/agi/features/conversation.d.ts.map +1 -0
- package/dist/agi/features/docs-reader.d.ts +72 -0
- package/dist/agi/features/docs-reader.d.ts.map +1 -0
- package/dist/agi/features/file-tools.d.ts +110 -0
- package/dist/agi/features/file-tools.d.ts.map +1 -0
- package/dist/agi/features/luca-coder.d.ts +323 -0
- package/dist/agi/features/luca-coder.d.ts.map +1 -0
- package/dist/agi/features/openai-codex.d.ts +381 -0
- package/dist/agi/features/openai-codex.d.ts.map +1 -0
- package/dist/agi/features/openapi.d.ts +200 -0
- package/dist/agi/features/openapi.d.ts.map +1 -0
- package/dist/agi/features/skills-library.d.ts +167 -0
- package/dist/agi/features/skills-library.d.ts.map +1 -0
- package/dist/agi/index.d.ts +5 -0
- package/dist/agi/index.d.ts.map +1 -0
- package/dist/agi/lib/interceptor-chain.d.ts +44 -0
- package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
- package/dist/agi/lib/token-counter.d.ts +13 -0
- package/dist/agi/lib/token-counter.d.ts.map +1 -0
- package/dist/bootstrap/generated.d.ts +5 -0
- package/dist/bootstrap/generated.d.ts.map +1 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/bus.d.ts +29 -0
- package/dist/bus.d.ts.map +1 -0
- package/dist/cli/build-info.d.ts +4 -0
- package/dist/cli/build-info.d.ts.map +1 -0
- package/dist/cli/cli.d.ts +3 -12
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/client.d.ts +60 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/clients/civitai/index.d.ts +472 -0
- package/dist/clients/civitai/index.d.ts.map +1 -0
- package/dist/clients/client-template.d.ts +30 -0
- package/dist/clients/client-template.d.ts.map +1 -0
- package/dist/clients/comfyui/index.d.ts +281 -0
- package/dist/clients/comfyui/index.d.ts.map +1 -0
- package/dist/clients/elevenlabs/index.d.ts +197 -0
- package/dist/clients/elevenlabs/index.d.ts.map +1 -0
- package/dist/clients/graph.d.ts +64 -0
- package/dist/clients/graph.d.ts.map +1 -0
- package/dist/clients/openai/index.d.ts +247 -0
- package/dist/clients/openai/index.d.ts.map +1 -0
- package/dist/clients/rest.d.ts +92 -0
- package/dist/clients/rest.d.ts.map +1 -0
- package/dist/clients/supabase/index.d.ts +176 -0
- package/dist/clients/supabase/index.d.ts.map +1 -0
- package/dist/clients/websocket.d.ts +127 -0
- package/dist/clients/websocket.d.ts.map +1 -0
- package/dist/command.d.ts +163 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/commands/bootstrap.d.ts +20 -0
- package/dist/commands/bootstrap.d.ts.map +1 -0
- package/dist/commands/chat.d.ts +37 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/code.d.ts +28 -0
- package/dist/commands/code.d.ts.map +1 -0
- package/dist/commands/console.d.ts +22 -0
- package/dist/commands/console.d.ts.map +1 -0
- package/dist/commands/describe.d.ts +50 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/eval.d.ts +23 -0
- package/dist/commands/eval.d.ts.map +1 -0
- package/dist/commands/help.d.ts +25 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/index.d.ts +18 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/introspect.d.ts +24 -0
- package/dist/commands/introspect.d.ts.map +1 -0
- package/dist/commands/mcp.d.ts +35 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/prompt.d.ts +38 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/run.d.ts +24 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/sandbox-mcp.d.ts +34 -0
- package/dist/commands/sandbox-mcp.d.ts.map +1 -0
- package/dist/commands/save-api-docs.d.ts +21 -0
- package/dist/commands/save-api-docs.d.ts.map +1 -0
- package/dist/commands/scaffold.d.ts +24 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/select.d.ts +22 -0
- package/dist/commands/select.d.ts.map +1 -0
- package/dist/commands/serve.d.ts +29 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/container-describer.d.ts +144 -0
- package/dist/container-describer.d.ts.map +1 -0
- package/dist/container.d.ts +451 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/endpoint.d.ts +113 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/feature.d.ts +47 -0
- package/dist/feature.d.ts.map +1 -0
- package/dist/graft.d.ts +29 -0
- package/dist/graft.d.ts.map +1 -0
- package/dist/hash-object.d.ts +8 -0
- package/dist/hash-object.d.ts.map +1 -0
- package/dist/helper.d.ts +209 -0
- package/dist/helper.d.ts.map +1 -0
- package/dist/introspection/generated.node.d.ts +44623 -0
- package/dist/introspection/generated.node.d.ts.map +1 -0
- package/dist/introspection/generated.web.d.ts +1412 -0
- package/dist/introspection/generated.web.d.ts.map +1 -0
- package/dist/introspection/index.d.ts +156 -0
- package/dist/introspection/index.d.ts.map +1 -0
- package/dist/introspection/scan.d.ts +147 -0
- package/dist/introspection/scan.d.ts.map +1 -0
- package/dist/node/container.d.ts +256 -0
- package/dist/node/container.d.ts.map +1 -0
- package/dist/node/feature.d.ts +9 -0
- package/dist/node/feature.d.ts.map +1 -0
- package/dist/node/features/container-link.d.ts +213 -0
- package/dist/node/features/container-link.d.ts.map +1 -0
- package/dist/node/features/content-db.d.ts +354 -0
- package/dist/node/features/content-db.d.ts.map +1 -0
- package/dist/node/features/disk-cache.d.ts +236 -0
- package/dist/node/features/disk-cache.d.ts.map +1 -0
- package/dist/node/features/dns.d.ts +511 -0
- package/dist/node/features/dns.d.ts.map +1 -0
- package/dist/node/features/docker.d.ts +485 -0
- package/dist/node/features/docker.d.ts.map +1 -0
- package/dist/node/features/downloader.d.ts +73 -0
- package/dist/node/features/downloader.d.ts.map +1 -0
- package/dist/node/features/figlet-fonts.d.ts +4 -0
- package/dist/node/features/figlet-fonts.d.ts.map +1 -0
- package/dist/node/features/file-manager.d.ts +177 -0
- package/dist/node/features/file-manager.d.ts.map +1 -0
- package/dist/node/features/fs.d.ts +635 -0
- package/dist/node/features/fs.d.ts.map +1 -0
- package/dist/node/features/git.d.ts +329 -0
- package/dist/node/features/git.d.ts.map +1 -0
- package/dist/node/features/google-auth.d.ts +200 -0
- package/dist/node/features/google-auth.d.ts.map +1 -0
- package/dist/node/features/google-calendar.d.ts +194 -0
- package/dist/node/features/google-calendar.d.ts.map +1 -0
- package/dist/node/features/google-docs.d.ts +138 -0
- package/dist/node/features/google-docs.d.ts.map +1 -0
- package/dist/node/features/google-drive.d.ts +202 -0
- package/dist/node/features/google-drive.d.ts.map +1 -0
- package/dist/node/features/google-mail.d.ts +221 -0
- package/dist/node/features/google-mail.d.ts.map +1 -0
- package/dist/node/features/google-sheets.d.ts +157 -0
- package/dist/node/features/google-sheets.d.ts.map +1 -0
- package/dist/node/features/grep.d.ts +207 -0
- package/dist/node/features/grep.d.ts.map +1 -0
- package/dist/node/features/helpers.d.ts +236 -0
- package/dist/node/features/helpers.d.ts.map +1 -0
- package/dist/node/features/ink.d.ts +332 -0
- package/dist/node/features/ink.d.ts.map +1 -0
- package/dist/node/features/ipc-socket.d.ts +298 -0
- package/dist/node/features/ipc-socket.d.ts.map +1 -0
- package/dist/node/features/json-tree.d.ts +140 -0
- package/dist/node/features/json-tree.d.ts.map +1 -0
- package/dist/node/features/networking.d.ts +373 -0
- package/dist/node/features/networking.d.ts.map +1 -0
- package/dist/node/features/nlp.d.ts +125 -0
- package/dist/node/features/nlp.d.ts.map +1 -0
- package/dist/node/features/opener.d.ts +93 -0
- package/dist/node/features/opener.d.ts.map +1 -0
- package/dist/node/features/os.d.ts +168 -0
- package/dist/node/features/os.d.ts.map +1 -0
- package/dist/node/features/package-finder.d.ts +419 -0
- package/dist/node/features/package-finder.d.ts.map +1 -0
- package/dist/node/features/postgres.d.ts +173 -0
- package/dist/node/features/postgres.d.ts.map +1 -0
- package/dist/node/features/proc.d.ts +285 -0
- package/dist/node/features/proc.d.ts.map +1 -0
- package/dist/node/features/process-manager.d.ts +427 -0
- package/dist/node/features/process-manager.d.ts.map +1 -0
- package/dist/node/features/python.d.ts +477 -0
- package/dist/node/features/python.d.ts.map +1 -0
- package/dist/node/features/redis.d.ts +247 -0
- package/dist/node/features/redis.d.ts.map +1 -0
- package/dist/node/features/repl.d.ts +84 -0
- package/dist/node/features/repl.d.ts.map +1 -0
- package/dist/node/features/runpod.d.ts +527 -0
- package/dist/node/features/runpod.d.ts.map +1 -0
- package/dist/node/features/secure-shell.d.ts +145 -0
- package/dist/node/features/secure-shell.d.ts.map +1 -0
- package/dist/node/features/semantic-search.d.ts +207 -0
- package/dist/node/features/semantic-search.d.ts.map +1 -0
- package/dist/node/features/sqlite.d.ts +180 -0
- package/dist/node/features/sqlite.d.ts.map +1 -0
- package/dist/node/features/telegram.d.ts +173 -0
- package/dist/node/features/telegram.d.ts.map +1 -0
- package/dist/node/features/transpiler.d.ts +51 -0
- package/dist/node/features/transpiler.d.ts.map +1 -0
- package/dist/node/features/tts.d.ts +108 -0
- package/dist/node/features/tts.d.ts.map +1 -0
- package/dist/node/features/ui.d.ts +562 -0
- package/dist/node/features/ui.d.ts.map +1 -0
- package/dist/node/features/vault.d.ts +90 -0
- package/dist/node/features/vault.d.ts.map +1 -0
- package/dist/node/features/vm.d.ts +285 -0
- package/dist/node/features/vm.d.ts.map +1 -0
- package/dist/node/features/yaml-tree.d.ts +118 -0
- package/dist/node/features/yaml-tree.d.ts.map +1 -0
- package/dist/node/features/yaml.d.ts +127 -0
- package/dist/node/features/yaml.d.ts.map +1 -0
- package/dist/node.d.ts +67 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/python/generated.d.ts +2 -0
- package/dist/python/generated.d.ts.map +1 -0
- package/dist/react/index.d.ts +36 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/registry.d.ts +97 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/scaffolds/generated.d.ts +13 -0
- package/dist/scaffolds/generated.d.ts.map +1 -0
- package/dist/scaffolds/template.d.ts +11 -0
- package/dist/scaffolds/template.d.ts.map +1 -0
- package/dist/schemas/base.d.ts +254 -0
- package/dist/schemas/base.d.ts.map +1 -0
- package/dist/selector.d.ts +130 -0
- package/dist/selector.d.ts.map +1 -0
- package/dist/server.d.ts +89 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/servers/express.d.ts +104 -0
- package/dist/servers/express.d.ts.map +1 -0
- package/dist/servers/mcp.d.ts +201 -0
- package/dist/servers/mcp.d.ts.map +1 -0
- package/dist/servers/socket.d.ts +121 -0
- package/dist/servers/socket.d.ts.map +1 -0
- package/dist/state.d.ts +24 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/web/clients/socket.d.ts +37 -0
- package/dist/web/clients/socket.d.ts.map +1 -0
- package/dist/web/container.d.ts +55 -0
- package/dist/web/container.d.ts.map +1 -0
- package/dist/web/extension.d.ts +4 -0
- package/dist/web/extension.d.ts.map +1 -0
- package/dist/web/feature.d.ts +8 -0
- package/dist/web/feature.d.ts.map +1 -0
- package/dist/web/features/asset-loader.d.ts +35 -0
- package/dist/web/features/asset-loader.d.ts.map +1 -0
- package/dist/web/features/container-link.d.ts +167 -0
- package/dist/web/features/container-link.d.ts.map +1 -0
- package/dist/web/features/esbuild.d.ts +51 -0
- package/dist/web/features/esbuild.d.ts.map +1 -0
- package/dist/web/features/helpers.d.ts +140 -0
- package/dist/web/features/helpers.d.ts.map +1 -0
- package/dist/web/features/network.d.ts +69 -0
- package/dist/web/features/network.d.ts.map +1 -0
- package/dist/web/features/speech.d.ts +71 -0
- package/dist/web/features/speech.d.ts.map +1 -0
- package/dist/web/features/vault.d.ts +62 -0
- package/dist/web/features/vault.d.ts.map +1 -0
- package/dist/web/features/vm.d.ts +48 -0
- package/dist/web/features/vm.d.ts.map +1 -0
- package/dist/web/features/voice-recognition.d.ts +96 -0
- package/dist/web/features/voice-recognition.d.ts.map +1 -0
- package/dist/web/shims/isomorphic-vm.d.ts +22 -0
- package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
- package/index.html +1457 -0
- package/index.ts +1 -0
- package/install.sh +84 -0
- package/luca.cli.ts +16 -0
- package/luca.console.ts +9 -0
- package/main.py +6 -0
- package/package.json +219 -58
- package/public/index.html +1457 -0
- package/public/slides-ai-native.html +902 -0
- package/public/slides-intro.html +974 -0
- package/pyproject.toml +7 -0
- package/scripts/build-web.ts +28 -0
- package/scripts/examples/ask-luca-expert.ts +42 -0
- package/scripts/examples/assistant-questions.ts +12 -0
- package/scripts/examples/excalidraw-expert.ts +75 -0
- package/scripts/examples/expert-chat.ts +0 -0
- package/scripts/examples/file-manager.ts +14 -0
- package/scripts/examples/ideas.ts +12 -0
- package/scripts/examples/interactive-chat.ts +20 -0
- package/scripts/examples/openai-tool-calls.ts +113 -0
- package/scripts/examples/opening-a-web-browser.ts +5 -0
- package/scripts/examples/telegram-bot.ts +79 -0
- package/scripts/examples/using-assistant-with-mcp.ts +555 -0
- package/scripts/examples/using-claude-code.ts +10 -0
- package/scripts/examples/using-contentdb.ts +35 -0
- package/scripts/examples/using-conversations.ts +35 -0
- package/scripts/examples/using-disk-cache.ts +10 -0
- package/scripts/examples/using-docker-shell.ts +75 -0
- package/scripts/examples/using-elevenlabs.ts +25 -0
- package/scripts/examples/using-google-calendar.ts +57 -0
- package/scripts/examples/using-google-docs.ts +74 -0
- package/scripts/examples/using-google-drive.ts +74 -0
- package/scripts/examples/using-google-sheets.ts +89 -0
- package/scripts/examples/using-nlp.ts +55 -0
- package/scripts/examples/using-ollama.ts +11 -0
- package/scripts/examples/using-postgres.ts +55 -0
- package/scripts/examples/using-runpod.ts +32 -0
- package/scripts/examples/using-tts.ts +40 -0
- package/scripts/scaffold.ts +391 -0
- package/scripts/scratch.ts +15 -0
- package/scripts/stamp-build.sh +12 -0
- package/scripts/test-assistant-hooks.ts +13 -0
- package/scripts/test-docs-reader.ts +10 -0
- package/scripts/test-linux-binary.sh +80 -0
- package/scripts/update-introspection-data.ts +58 -0
- package/src/agi/README.md +14 -0
- package/src/agi/container.server.ts +156 -0
- package/src/agi/feature.ts +13 -0
- package/src/agi/features/agent-memory.ts +694 -0
- package/src/agi/features/assistant.ts +1653 -0
- package/src/agi/features/assistants-manager.ts +534 -0
- package/src/agi/features/autonomous-assistant.ts +431 -0
- package/src/agi/features/browser-use.ts +672 -0
- package/src/agi/features/claude-code.ts +1584 -0
- package/src/agi/features/coding-tools.ts +175 -0
- package/src/agi/features/conversation-history.ts +672 -0
- package/src/agi/features/conversation.ts +1494 -0
- package/src/agi/features/docs-reader.ts +167 -0
- package/src/agi/features/file-tools.ts +340 -0
- package/src/agi/features/luca-coder.ts +641 -0
- package/src/agi/features/mcp-bridge.ts +532 -0
- package/src/agi/features/openai-codex.ts +651 -0
- package/src/agi/features/openapi.ts +445 -0
- package/src/agi/features/skills-library.ts +557 -0
- package/src/agi/index.ts +6 -0
- package/src/agi/lib/interceptor-chain.ts +89 -0
- package/src/agi/lib/token-counter.ts +202 -0
- package/src/bootstrap/generated.ts +9791 -0
- package/src/browser.ts +25 -0
- package/src/bus.ts +122 -0
- package/src/cli/build-info.ts +4 -0
- package/src/cli/cli.ts +355 -0
- package/src/client.ts +170 -0
- package/src/clients/civitai/index.ts +537 -0
- package/src/clients/client-template.ts +41 -0
- package/src/clients/comfyui/index.ts +604 -0
- package/src/clients/elevenlabs/index.ts +317 -0
- package/src/clients/graph.ts +87 -0
- package/src/clients/openai/index.ts +456 -0
- package/src/clients/rest.ts +207 -0
- package/src/clients/supabase/index.ts +357 -0
- package/src/clients/voicebox/index.ts +300 -0
- package/src/clients/websocket.ts +251 -0
- package/src/command.ts +506 -0
- package/src/commands/bootstrap.ts +244 -0
- package/src/commands/chat.ts +309 -0
- package/src/commands/code.ts +371 -0
- package/src/commands/console.ts +189 -0
- package/src/commands/describe.ts +243 -0
- package/src/commands/eval.ts +67 -0
- package/src/commands/help.ts +240 -0
- package/src/commands/index.ts +19 -0
- package/src/commands/introspect.ts +218 -0
- package/src/commands/mcp.ts +64 -0
- package/src/commands/prompt.ts +1014 -0
- package/src/commands/run.ts +278 -0
- package/src/commands/sandbox-mcp.ts +343 -0
- package/src/commands/save-api-docs.ts +51 -0
- package/src/commands/scaffold.ts +225 -0
- package/src/commands/select.ts +99 -0
- package/src/commands/serve.ts +208 -0
- package/src/container-describer.ts +1091 -0
- package/src/container.ts +1199 -0
- package/src/endpoint.ts +365 -0
- package/src/entity.ts +173 -0
- package/src/feature.ts +118 -0
- package/src/graft.ts +181 -0
- package/src/hash-object.ts +97 -0
- package/src/helper.ts +849 -0
- package/src/introspection/generated.agi.ts +41200 -0
- package/src/introspection/generated.node.ts +28773 -0
- package/src/introspection/generated.web.ts +2272 -0
- package/src/introspection/index.ts +296 -0
- package/src/introspection/scan.ts +1136 -0
- package/src/node/container.ts +409 -0
- package/src/node/feature.ts +13 -0
- package/src/node/features/container-link.ts +559 -0
- package/src/node/features/content-db.ts +849 -0
- package/src/node/features/disk-cache.ts +388 -0
- package/src/node/features/display-result.ts +57 -0
- package/src/node/features/dns.ts +669 -0
- package/src/node/features/docker.ts +921 -0
- package/src/node/features/downloader.ts +79 -0
- package/src/node/features/figlet-fonts.ts +600 -0
- package/src/node/features/file-manager.ts +535 -0
- package/src/node/features/fs.ts +1050 -0
- package/src/node/features/git.ts +592 -0
- package/src/node/features/google-auth.ts +504 -0
- package/src/node/features/google-calendar.ts +306 -0
- package/src/node/features/google-docs.ts +412 -0
- package/src/node/features/google-drive.ts +346 -0
- package/src/node/features/google-mail.ts +540 -0
- package/src/node/features/google-sheets.ts +286 -0
- package/src/node/features/grep.ts +427 -0
- package/src/node/features/helpers.ts +762 -0
- package/src/node/features/ink.ts +490 -0
- package/src/node/features/ipc-socket.ts +649 -0
- package/src/node/features/json-tree.ts +170 -0
- package/src/node/features/networking.ts +961 -0
- package/src/node/features/nlp.ts +212 -0
- package/src/node/features/opener.ts +180 -0
- package/src/node/features/os.ts +403 -0
- package/src/node/features/package-finder.ts +540 -0
- package/src/node/features/postgres.ts +289 -0
- package/src/node/features/proc.ts +503 -0
- package/src/node/features/process-manager.ts +844 -0
- package/src/node/features/python.ts +912 -0
- package/src/node/features/redis.ts +446 -0
- package/src/node/features/repl.ts +212 -0
- package/src/node/features/runpod.ts +811 -0
- package/src/node/features/secure-shell.ts +261 -0
- package/src/node/features/semantic-search.ts +935 -0
- package/src/node/features/sqlite.ts +289 -0
- package/src/node/features/telegram.ts +343 -0
- package/src/node/features/transpiler.ts +160 -0
- package/src/node/features/tts.ts +185 -0
- package/src/node/features/ui.ts +791 -0
- package/src/node/features/vault.ts +153 -0
- package/src/node/features/vm.ts +462 -0
- package/src/node/features/yaml-tree.ts +148 -0
- package/src/node/features/yaml.ts +133 -0
- package/src/node.ts +76 -0
- package/src/python/bridge.py +220 -0
- package/src/python/generated.ts +226 -0
- package/src/react/index.ts +175 -0
- package/src/registry.ts +210 -0
- package/src/scaffolds/generated.ts +1814 -0
- package/src/scaffolds/template.ts +46 -0
- package/src/schemas/base.ts +296 -0
- package/src/selector.ts +352 -0
- package/src/server.ts +229 -0
- package/src/servers/express.ts +283 -0
- package/src/servers/mcp.ts +802 -0
- package/src/servers/socket.ts +258 -0
- package/src/state.ts +101 -0
- package/src/web/clients/socket.ts +99 -0
- package/src/web/container.ts +75 -0
- package/src/web/extension.ts +30 -0
- package/src/web/feature.ts +12 -0
- package/src/web/features/asset-loader.ts +72 -0
- package/src/web/features/container-link.ts +382 -0
- package/src/web/features/esbuild.ts +93 -0
- package/src/web/features/helpers.ts +291 -0
- package/src/web/features/network.ts +85 -0
- package/src/web/features/speech.ts +104 -0
- package/src/web/features/vault.ts +207 -0
- package/src/web/features/vm.ts +85 -0
- package/src/web/features/voice-recognition.ts +161 -0
- package/src/web/shims/isomorphic-vm.ts +149 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +58 -0
- package/uv.lock +8 -0
- package/LICENSE +0 -21
- package/dist/cli/cli.js +0 -48
- package/dist/cli/common.d.ts +0 -2
- package/dist/cli/common.js +0 -6
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -5
- package/dist/cli/run.d.ts +0 -1
- package/dist/cli/run.js +0 -38
- package/dist/core/index.d.ts +0 -4
- package/dist/core/index.js +0 -32
- package/dist/core/read.d.ts +0 -2
- package/dist/core/read.js +0 -29
- package/dist/core/request.d.ts +0 -1
- package/dist/core/request.js +0 -2
- package/dist/core/write.d.ts +0 -2
- package/dist/core/write.js +0 -21
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -5
- package/dist/utils/common.d.ts +0 -9
- package/dist/utils/common.js +0 -57
- package/dist/utils/consts.d.ts +0 -3
- package/dist/utils/consts.js +0 -11
- package/dist/utils/dict.d.ts +0 -1
- package/dist/utils/dict.js +0 -7
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/index.js +0 -21
- package/dist/utils/log.d.ts +0 -1
- package/dist/utils/log.js +0 -5
- package/dist/utils/types.d.ts +0 -1
- package/dist/utils/types.js +0 -2
- package/dist/utils/utils.test.d.ts +0 -1
- package/dist/utils/utils.test.js +0 -7
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
import type { NodeContainer } from '../node/container.js'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import { MCPServerStateSchema, MCPServerOptionsSchema, MCPServerEventsSchema } from '../schemas/base.js'
|
|
4
|
+
import { Server } from '../server.js'
|
|
5
|
+
import { Server as MCPProtocolServer } from '@modelcontextprotocol/sdk/server/index.js'
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
7
|
+
import {
|
|
8
|
+
ListToolsRequestSchema,
|
|
9
|
+
CallToolRequestSchema,
|
|
10
|
+
ListResourcesRequestSchema,
|
|
11
|
+
ReadResourceRequestSchema,
|
|
12
|
+
ListPromptsRequestSchema,
|
|
13
|
+
GetPromptRequestSchema,
|
|
14
|
+
JSONRPCMessageSchema,
|
|
15
|
+
} from '@modelcontextprotocol/sdk/types.js'
|
|
16
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'
|
|
17
|
+
|
|
18
|
+
declare module '../server' {
|
|
19
|
+
interface AvailableServers {
|
|
20
|
+
mcp: typeof MCPServer
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type MCPServerOptions = z.infer<typeof MCPServerOptionsSchema>
|
|
25
|
+
export type MCPServerState = z.infer<typeof MCPServerStateSchema>
|
|
26
|
+
|
|
27
|
+
/** Context object passed to all MCP tool, resource, and prompt handlers. */
|
|
28
|
+
export type MCPContext = {
|
|
29
|
+
container: NodeContainer
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A registered MCP tool with its schema, handler, and pre-computed JSON Schema. */
|
|
33
|
+
export interface RegisteredTool {
|
|
34
|
+
name: string
|
|
35
|
+
description?: string
|
|
36
|
+
schema?: z.ZodType
|
|
37
|
+
jsonSchema?: Record<string, any>
|
|
38
|
+
handler: Function
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** A registered MCP resource with its URI, metadata, and handler. */
|
|
42
|
+
export interface RegisteredResource {
|
|
43
|
+
uri: string
|
|
44
|
+
name?: string
|
|
45
|
+
description?: string
|
|
46
|
+
mimeType?: string
|
|
47
|
+
handler: (uri: string, ctx: MCPContext) => Promise<string> | string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A registered MCP prompt with its argument schemas and handler. */
|
|
51
|
+
export interface RegisteredPrompt {
|
|
52
|
+
name: string
|
|
53
|
+
description?: string
|
|
54
|
+
args?: Record<string, z.ZodType>
|
|
55
|
+
handler: (args: Record<string, string | undefined>, ctx: MCPContext) => Promise<PromptMessage[]> | PromptMessage[]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type PromptMessage = {
|
|
59
|
+
role: 'user' | 'assistant'
|
|
60
|
+
content: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type ToolRegistrationOptions = {
|
|
64
|
+
schema?: z.ZodType
|
|
65
|
+
description?: string
|
|
66
|
+
handler?: Function | ((args: any, ctx: any) => any)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type ResourceRegistrationOptions = {
|
|
70
|
+
name?: string
|
|
71
|
+
description?: string
|
|
72
|
+
mimeType?: string
|
|
73
|
+
handler: (uri: string, ctx: MCPContext) => Promise<string> | string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type PromptRegistrationOptions = {
|
|
77
|
+
description?: string
|
|
78
|
+
args?: Record<string, z.ZodType>
|
|
79
|
+
handler: (args: Record<string, string | undefined>, ctx: MCPContext) => Promise<PromptMessage[]> | PromptMessage[]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type MCPCompatMode = 'standard' | 'codex'
|
|
83
|
+
type StdioCompatMode = 'standard' | 'codex' | 'auto'
|
|
84
|
+
|
|
85
|
+
const SKIP_MESSAGE = Symbol('skip-message')
|
|
86
|
+
|
|
87
|
+
class CompatStdioServerTransport {
|
|
88
|
+
private _readBuffer: Buffer | undefined
|
|
89
|
+
private _started = false
|
|
90
|
+
private _inputFormat: 'framed' | 'line' | undefined
|
|
91
|
+
|
|
92
|
+
onmessage?: (message: any) => void
|
|
93
|
+
onerror?: (error: Error) => void
|
|
94
|
+
onclose?: () => void
|
|
95
|
+
|
|
96
|
+
constructor(
|
|
97
|
+
private readonly mode: Exclude<StdioCompatMode, 'standard'>,
|
|
98
|
+
private readonly _stdin = process.stdin,
|
|
99
|
+
private readonly _stdout = process.stdout,
|
|
100
|
+
) {}
|
|
101
|
+
|
|
102
|
+
private _ondata = (chunk: Buffer) => {
|
|
103
|
+
this._readBuffer = this._readBuffer ? Buffer.concat([this._readBuffer, chunk]) : chunk
|
|
104
|
+
this.processReadBuffer()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private _onerror = (error: Error) => {
|
|
108
|
+
this.onerror?.(error)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async start() {
|
|
112
|
+
if (this._started) {
|
|
113
|
+
throw new Error('CompatStdioServerTransport already started')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this._started = true
|
|
117
|
+
this._stdin.on('data', this._ondata)
|
|
118
|
+
this._stdin.on('error', this._onerror)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private processReadBuffer() {
|
|
122
|
+
while (true) {
|
|
123
|
+
try {
|
|
124
|
+
const message = this._tryReadMessage()
|
|
125
|
+
if (message === null) break
|
|
126
|
+
if (message === SKIP_MESSAGE) continue
|
|
127
|
+
this.onmessage?.(message)
|
|
128
|
+
} catch (error) {
|
|
129
|
+
this.onerror?.(error as Error)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private _tryReadMessage(): any | typeof SKIP_MESSAGE | null {
|
|
135
|
+
if (!this._readBuffer || this._readBuffer.length === 0) {
|
|
136
|
+
return null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const format = this._resolveInputFormat()
|
|
140
|
+
if (!format) return null
|
|
141
|
+
|
|
142
|
+
if (format === 'framed') {
|
|
143
|
+
return this._readFramedMessage()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return this._readLineMessage()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private _resolveInputFormat(): 'framed' | 'line' | undefined {
|
|
150
|
+
if (this._inputFormat) {
|
|
151
|
+
return this._inputFormat
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!this._readBuffer || this._readBuffer.length === 0) {
|
|
155
|
+
return undefined
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const prefix = this._readBuffer.toString('utf8', 0, Math.min(this._readBuffer.length, 128))
|
|
159
|
+
if (/^\s*Content-Length\s*:/i.test(prefix)) {
|
|
160
|
+
this._inputFormat = 'framed'
|
|
161
|
+
return this._inputFormat
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const firstByte = this._readBuffer.find((b) => ![0x20, 0x09, 0x0d, 0x0a].includes(b))
|
|
165
|
+
if (firstByte === undefined) return undefined
|
|
166
|
+
|
|
167
|
+
if (firstByte === 0x7b || firstByte === 0x5b) {
|
|
168
|
+
this._inputFormat = 'line'
|
|
169
|
+
return this._inputFormat
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (this._readBuffer.indexOf('\n') !== -1) {
|
|
173
|
+
this._inputFormat = 'line'
|
|
174
|
+
return this._inputFormat
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return undefined
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private _readFramedMessage(): any | null {
|
|
181
|
+
if (!this._readBuffer) return null
|
|
182
|
+
|
|
183
|
+
const crlfHeaderEnd = this._readBuffer.indexOf('\r\n\r\n')
|
|
184
|
+
const lfHeaderEnd = this._readBuffer.indexOf('\n\n')
|
|
185
|
+
|
|
186
|
+
if (crlfHeaderEnd === -1 && lfHeaderEnd === -1) {
|
|
187
|
+
return null
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let headerEnd = crlfHeaderEnd
|
|
191
|
+
let headerSeparatorLength = 4
|
|
192
|
+
|
|
193
|
+
if (headerEnd === -1 || (lfHeaderEnd !== -1 && lfHeaderEnd < headerEnd)) {
|
|
194
|
+
headerEnd = lfHeaderEnd
|
|
195
|
+
headerSeparatorLength = 2
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const headerText = this._readBuffer.toString('utf8', 0, headerEnd)
|
|
199
|
+
const headers = headerText.split(/\r?\n/)
|
|
200
|
+
const lengthHeader = headers.find((line) => /^content-length\s*:/i.test(line))
|
|
201
|
+
if (!lengthHeader) {
|
|
202
|
+
throw new Error('Missing Content-Length header in framed stdio message')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const length = Number(lengthHeader.split(':')[1]?.trim())
|
|
206
|
+
if (!Number.isFinite(length) || length < 0) {
|
|
207
|
+
throw new Error(`Invalid Content-Length value: ${lengthHeader}`)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const bodyStart = headerEnd + headerSeparatorLength
|
|
211
|
+
const bodyEnd = bodyStart + length
|
|
212
|
+
if (this._readBuffer.length < bodyEnd) {
|
|
213
|
+
return null
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const body = this._readBuffer.toString('utf8', bodyStart, bodyEnd)
|
|
217
|
+
this._readBuffer = this._readBuffer.subarray(bodyEnd)
|
|
218
|
+
|
|
219
|
+
return JSONRPCMessageSchema.parse(JSON.parse(body))
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private _readLineMessage(): any | typeof SKIP_MESSAGE | null {
|
|
223
|
+
if (!this._readBuffer) return null
|
|
224
|
+
|
|
225
|
+
const newlineIndex = this._readBuffer.indexOf('\n')
|
|
226
|
+
if (newlineIndex === -1) {
|
|
227
|
+
return null
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const line = this._readBuffer.toString('utf8', 0, newlineIndex).replace(/\r$/, '')
|
|
231
|
+
this._readBuffer = this._readBuffer.subarray(newlineIndex + 1)
|
|
232
|
+
|
|
233
|
+
if (line.trim() === '') {
|
|
234
|
+
return SKIP_MESSAGE
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return JSONRPCMessageSchema.parse(JSON.parse(line))
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async close() {
|
|
241
|
+
this._stdin.off('data', this._ondata)
|
|
242
|
+
this._stdin.off('error', this._onerror)
|
|
243
|
+
|
|
244
|
+
if (this._stdin.listenerCount('data') === 0) {
|
|
245
|
+
this._stdin.pause()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
this._readBuffer = undefined
|
|
249
|
+
this.onclose?.()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
send(message: any) {
|
|
253
|
+
return new Promise<void>((resolve) => {
|
|
254
|
+
const json = JSON.stringify(message)
|
|
255
|
+
const useFramed = this._inputFormat === 'line'
|
|
256
|
+
? false
|
|
257
|
+
: (this.mode === 'codex' || this._inputFormat === 'framed')
|
|
258
|
+
const payload = useFramed
|
|
259
|
+
? `Content-Length: ${Buffer.byteLength(json, 'utf8')}\r\n\r\n${json}`
|
|
260
|
+
: `${json}\n`
|
|
261
|
+
|
|
262
|
+
if (this._stdout.write(payload)) {
|
|
263
|
+
resolve()
|
|
264
|
+
} else {
|
|
265
|
+
this._stdout.once('drain', resolve)
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* MCP (Model Context Protocol) server for exposing tools, resources, and prompts
|
|
273
|
+
* to AI clients like Claude Code. Uses the low-level MCP SDK Server class directly
|
|
274
|
+
* with Zod 4 native JSON Schema conversion.
|
|
275
|
+
*
|
|
276
|
+
* Register tools, resources, and prompts programmatically, then start the server
|
|
277
|
+
* over stdio (for CLI integration) or HTTP (for remote access).
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* const mcp = container.server('mcp', { serverName: 'my-server', serverVersion: '1.0.0' })
|
|
282
|
+
*
|
|
283
|
+
* mcp.tool('search_files', {
|
|
284
|
+
* schema: z.object({ pattern: z.string() }),
|
|
285
|
+
* description: 'Search for files',
|
|
286
|
+
* handler: async (args, ctx) => {
|
|
287
|
+
* return ctx.container.feature('fs').walk('.', { include: [args.pattern] }).files.join('\n')
|
|
288
|
+
* }
|
|
289
|
+
* })
|
|
290
|
+
*
|
|
291
|
+
* await mcp.start()
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
export class MCPServer extends Server<MCPServerState, MCPServerOptions> {
|
|
295
|
+
static override shortcut = 'servers.mcp' as const
|
|
296
|
+
static override stateSchema = MCPServerStateSchema
|
|
297
|
+
static override optionsSchema = MCPServerOptionsSchema
|
|
298
|
+
static override eventsSchema = MCPServerEventsSchema
|
|
299
|
+
|
|
300
|
+
static { Server.register(this, 'mcp') }
|
|
301
|
+
|
|
302
|
+
_mcpServer?: MCPProtocolServer
|
|
303
|
+
_tools: Map<string, RegisteredTool> = new Map()
|
|
304
|
+
_resources: Map<string, RegisteredResource> = new Map()
|
|
305
|
+
_prompts: Map<string, RegisteredPrompt> = new Map()
|
|
306
|
+
|
|
307
|
+
override get initialState(): MCPServerState {
|
|
308
|
+
return {
|
|
309
|
+
port: this.options.port,
|
|
310
|
+
listening: false,
|
|
311
|
+
configured: false,
|
|
312
|
+
stopped: false,
|
|
313
|
+
transport: undefined,
|
|
314
|
+
toolCount: 0,
|
|
315
|
+
resourceCount: 0,
|
|
316
|
+
promptCount: 0,
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** The underlying MCP protocol server instance. Created during configure(). */
|
|
321
|
+
get mcpServer(): MCPProtocolServer {
|
|
322
|
+
if (!this._mcpServer) {
|
|
323
|
+
this.configure()
|
|
324
|
+
}
|
|
325
|
+
return this._mcpServer!
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** The handler context passed to all tool, resource, and prompt handlers. */
|
|
329
|
+
get handlerContext(): MCPContext {
|
|
330
|
+
return { container: this.container }
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Register an MCP tool. The tool's Zod schema is converted to JSON Schema
|
|
335
|
+
* for the protocol listing, and used for runtime argument validation.
|
|
336
|
+
*
|
|
337
|
+
* Tool handlers can return a string (auto-wrapped as text content) or a
|
|
338
|
+
* full CallToolResult object for advanced responses (images, errors, etc).
|
|
339
|
+
*
|
|
340
|
+
* @param name - Unique tool name
|
|
341
|
+
* @param options - Tool schema, description, and handler
|
|
342
|
+
*/
|
|
343
|
+
override tool(name: string, options: ToolRegistrationOptions): this {
|
|
344
|
+
let jsonSchema: Record<string, any> | undefined
|
|
345
|
+
|
|
346
|
+
if (options.schema) {
|
|
347
|
+
const full = (options.schema as any).toJSONSchema() as Record<string, any>
|
|
348
|
+
jsonSchema = {
|
|
349
|
+
type: full.type || 'object',
|
|
350
|
+
properties: full.properties || {},
|
|
351
|
+
...(full.required ? { required: full.required } : {}),
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const registered: RegisteredTool = {
|
|
356
|
+
name,
|
|
357
|
+
description: options.description,
|
|
358
|
+
schema: options.schema,
|
|
359
|
+
jsonSchema,
|
|
360
|
+
handler: options.handler ?? (() => {}),
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
this._tools.set(name, registered)
|
|
364
|
+
this.state.set('toolCount', this._tools.size)
|
|
365
|
+
this.emit('toolRegistered', name)
|
|
366
|
+
|
|
367
|
+
return this
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Register an MCP resource. Resources expose data (files, configs, etc)
|
|
372
|
+
* that AI clients can read by URI.
|
|
373
|
+
*
|
|
374
|
+
* Accepts either a handler function directly or an options object with
|
|
375
|
+
* additional metadata (name, description, mimeType).
|
|
376
|
+
*
|
|
377
|
+
* @param uri - Unique resource URI (e.g. "project://readme")
|
|
378
|
+
* @param handlerOrOptions - Handler function or options object with handler
|
|
379
|
+
*/
|
|
380
|
+
resource(
|
|
381
|
+
uri: string,
|
|
382
|
+
handlerOrOptions: ResourceRegistrationOptions['handler'] | ResourceRegistrationOptions
|
|
383
|
+
): this {
|
|
384
|
+
let registered: RegisteredResource
|
|
385
|
+
|
|
386
|
+
if (typeof handlerOrOptions === 'function') {
|
|
387
|
+
registered = { uri, handler: handlerOrOptions }
|
|
388
|
+
} else {
|
|
389
|
+
registered = {
|
|
390
|
+
uri,
|
|
391
|
+
name: handlerOrOptions.name,
|
|
392
|
+
description: handlerOrOptions.description,
|
|
393
|
+
mimeType: handlerOrOptions.mimeType,
|
|
394
|
+
handler: handlerOrOptions.handler,
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
this._resources.set(uri, registered)
|
|
399
|
+
this.state.set('resourceCount', this._resources.size)
|
|
400
|
+
this.emit('resourceRegistered', uri)
|
|
401
|
+
|
|
402
|
+
return this
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Register an MCP prompt. Prompts are reusable message templates that
|
|
407
|
+
* AI clients can invoke with optional string arguments.
|
|
408
|
+
*
|
|
409
|
+
* @param name - Unique prompt name
|
|
410
|
+
* @param options - Prompt handler, optional args schema, and description
|
|
411
|
+
*/
|
|
412
|
+
prompt(name: string, options: PromptRegistrationOptions): this {
|
|
413
|
+
const registered: RegisteredPrompt = {
|
|
414
|
+
name,
|
|
415
|
+
description: options.description,
|
|
416
|
+
args: options.args,
|
|
417
|
+
handler: options.handler,
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this._prompts.set(name, registered)
|
|
421
|
+
this.state.set('promptCount', this._prompts.size)
|
|
422
|
+
this.emit('promptRegistered', name)
|
|
423
|
+
|
|
424
|
+
return this
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Configure the MCP protocol server and register all protocol handlers.
|
|
429
|
+
* Called automatically before start() if not already configured.
|
|
430
|
+
*/
|
|
431
|
+
override async configure(): Promise<this> {
|
|
432
|
+
if (this.isConfigured) return this
|
|
433
|
+
|
|
434
|
+
const serverName = this.options.serverName || this.container.manifest?.name || 'luca-mcp'
|
|
435
|
+
const serverVersion = this.options.serverVersion || this.container.manifest?.version || '1.0.0'
|
|
436
|
+
|
|
437
|
+
this._mcpServer = new MCPProtocolServer(
|
|
438
|
+
{ name: serverName, version: serverVersion },
|
|
439
|
+
{
|
|
440
|
+
capabilities: {
|
|
441
|
+
tools: {},
|
|
442
|
+
resources: {},
|
|
443
|
+
prompts: {},
|
|
444
|
+
},
|
|
445
|
+
}
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
this._registerToolHandlers()
|
|
449
|
+
this._registerResourceHandlers()
|
|
450
|
+
this._registerPromptHandlers()
|
|
451
|
+
|
|
452
|
+
this._mcpServer.onerror = (error) => {
|
|
453
|
+
console.error('[MCP Server Error]', error)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
this.state.set('configured', true)
|
|
457
|
+
return this
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Start the MCP server with the specified transport.
|
|
462
|
+
*
|
|
463
|
+
* @param options - Transport configuration. Defaults to stdio.
|
|
464
|
+
* @param options.transport - 'stdio' for CLI integration, 'http' for remote access
|
|
465
|
+
* @param options.port - Port for HTTP transport (default 3001)
|
|
466
|
+
*/
|
|
467
|
+
override async start(options?: {
|
|
468
|
+
transport?: 'stdio' | 'http'
|
|
469
|
+
port?: number
|
|
470
|
+
host?: string
|
|
471
|
+
mcpCompat?: MCPCompatMode
|
|
472
|
+
stdioCompat?: StdioCompatMode
|
|
473
|
+
}): Promise<this> {
|
|
474
|
+
if (this.isListening) return this
|
|
475
|
+
await this._drainPendingPlugins()
|
|
476
|
+
if (!this.isConfigured) await this.configure()
|
|
477
|
+
|
|
478
|
+
const transport = options?.transport || this.options.transport || 'stdio'
|
|
479
|
+
|
|
480
|
+
if (transport === 'stdio') {
|
|
481
|
+
const stdioCompat = this._resolveStdioCompat(options?.stdioCompat)
|
|
482
|
+
const stdioTransport = stdioCompat === 'standard'
|
|
483
|
+
? new StdioServerTransport()
|
|
484
|
+
: new CompatStdioServerTransport(stdioCompat)
|
|
485
|
+
await this.mcpServer.connect(stdioTransport)
|
|
486
|
+
this.state.set('transport', 'stdio')
|
|
487
|
+
} else if (transport === 'http') {
|
|
488
|
+
const port = options?.port || this.options.port || 3001
|
|
489
|
+
const compat = this._resolveMCPCompat(options?.mcpCompat)
|
|
490
|
+
await this._startHTTPTransport(port, compat)
|
|
491
|
+
this.state.set('transport', 'http')
|
|
492
|
+
this.state.set('port', port)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
this.state.set('listening', true)
|
|
496
|
+
return this
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Stop the MCP server and close all connections.
|
|
501
|
+
*/
|
|
502
|
+
override async stop(): Promise<this> {
|
|
503
|
+
if (this.isStopped) return this
|
|
504
|
+
|
|
505
|
+
if (this._mcpServer) {
|
|
506
|
+
await this._mcpServer.close()
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
this.state.set('listening', false)
|
|
510
|
+
this.state.set('stopped', true)
|
|
511
|
+
return this
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/** Register tools/list and tools/call protocol handlers on the MCP server. */
|
|
515
|
+
private _registerToolHandlers() {
|
|
516
|
+
this.mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
517
|
+
const tools = Array.from(this._tools.values()).map((t) => ({
|
|
518
|
+
name: t.name,
|
|
519
|
+
description: t.description || '',
|
|
520
|
+
inputSchema: t.jsonSchema || { type: 'object' as const, properties: {} },
|
|
521
|
+
}))
|
|
522
|
+
|
|
523
|
+
return { tools }
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
this.mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
527
|
+
const { name, arguments: args = {} } = request.params
|
|
528
|
+
|
|
529
|
+
const tool = this._tools.get(name)
|
|
530
|
+
if (!tool) {
|
|
531
|
+
return {
|
|
532
|
+
content: [{ type: 'text' as const, text: `Unknown tool: ${name}` }],
|
|
533
|
+
isError: true,
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
try {
|
|
538
|
+
// Validate arguments with Zod schema if provided
|
|
539
|
+
const validatedArgs = tool.schema ? tool.schema.parse(args) : args
|
|
540
|
+
|
|
541
|
+
this.emit('toolCalled', name, validatedArgs)
|
|
542
|
+
|
|
543
|
+
const result = await tool.handler(validatedArgs, this.handlerContext)
|
|
544
|
+
|
|
545
|
+
// Auto-wrap string results into text content
|
|
546
|
+
if (typeof result === 'string') {
|
|
547
|
+
return {
|
|
548
|
+
content: [{ type: 'text' as const, text: result }],
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Assume it's already a CallToolResult
|
|
553
|
+
return result as CallToolResult
|
|
554
|
+
} catch (error: any) {
|
|
555
|
+
return {
|
|
556
|
+
content: [{ type: 'text' as const, text: `Error calling tool ${name}: ${error.message}` }],
|
|
557
|
+
isError: true,
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
})
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/** Register resources/list and resources/read protocol handlers on the MCP server. */
|
|
564
|
+
private _registerResourceHandlers() {
|
|
565
|
+
this.mcpServer.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
566
|
+
const resources = Array.from(this._resources.values()).map((r) => ({
|
|
567
|
+
uri: r.uri,
|
|
568
|
+
name: r.name || r.uri,
|
|
569
|
+
description: r.description,
|
|
570
|
+
mimeType: r.mimeType,
|
|
571
|
+
}))
|
|
572
|
+
|
|
573
|
+
return { resources }
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
this.mcpServer.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
577
|
+
const { uri } = request.params
|
|
578
|
+
|
|
579
|
+
const resource = this._resources.get(uri)
|
|
580
|
+
if (!resource) {
|
|
581
|
+
throw new Error(`Unknown resource: ${uri}`)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const text = await resource.handler(uri, this.handlerContext)
|
|
585
|
+
|
|
586
|
+
return {
|
|
587
|
+
contents: [{
|
|
588
|
+
uri,
|
|
589
|
+
mimeType: resource.mimeType || 'text/plain',
|
|
590
|
+
text,
|
|
591
|
+
}],
|
|
592
|
+
}
|
|
593
|
+
})
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** Register prompts/list and prompts/get protocol handlers on the MCP server. */
|
|
597
|
+
private _registerPromptHandlers() {
|
|
598
|
+
this.mcpServer.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
599
|
+
const prompts = Array.from(this._prompts.values()).map((p) => ({
|
|
600
|
+
name: p.name,
|
|
601
|
+
description: p.description,
|
|
602
|
+
arguments: p.args
|
|
603
|
+
? Object.entries(p.args).map(([argName, schema]) => ({
|
|
604
|
+
name: argName,
|
|
605
|
+
description: (schema as any)._zod?.def?.description || '',
|
|
606
|
+
required: !(schema as any).isOptional?.(),
|
|
607
|
+
}))
|
|
608
|
+
: undefined,
|
|
609
|
+
}))
|
|
610
|
+
|
|
611
|
+
return { prompts }
|
|
612
|
+
})
|
|
613
|
+
|
|
614
|
+
this.mcpServer.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
615
|
+
const { name, arguments: args = {} } = request.params
|
|
616
|
+
|
|
617
|
+
const prompt = this._prompts.get(name)
|
|
618
|
+
if (!prompt) {
|
|
619
|
+
throw new Error(`Unknown prompt: ${name}`)
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const messages = await prompt.handler(args as Record<string, string | undefined>, this.handlerContext)
|
|
623
|
+
|
|
624
|
+
return {
|
|
625
|
+
messages: messages.map((m) => ({
|
|
626
|
+
role: m.role,
|
|
627
|
+
content: { type: 'text' as const, text: m.content },
|
|
628
|
+
})),
|
|
629
|
+
}
|
|
630
|
+
})
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** Start an HTTP transport using StreamableHTTPServerTransport. */
|
|
634
|
+
private async _startHTTPTransport(port: number, compat: MCPCompatMode): Promise<void> {
|
|
635
|
+
const { createServer } = await import('node:http')
|
|
636
|
+
const { StreamableHTTPServerTransport } = await import(
|
|
637
|
+
'@modelcontextprotocol/sdk/server/streamableHttp.js'
|
|
638
|
+
)
|
|
639
|
+
const { randomUUID } = await import('node:crypto')
|
|
640
|
+
|
|
641
|
+
const transport = new StreamableHTTPServerTransport({
|
|
642
|
+
sessionIdGenerator: compat === 'codex' ? undefined : () => randomUUID(),
|
|
643
|
+
enableJsonResponse: compat === 'codex',
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
const httpServer = createServer(async (req, res) => {
|
|
647
|
+
if (compat === 'codex') {
|
|
648
|
+
this._normalizeCodexRequest(req)
|
|
649
|
+
this._ensureJSONContentType(res)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Only handle the /mcp path
|
|
653
|
+
const url = new URL(req.url || '/', `http://localhost:${port}`)
|
|
654
|
+
|
|
655
|
+
if (url.pathname === '/mcp') {
|
|
656
|
+
// Parse body for POST requests
|
|
657
|
+
if (req.method === 'POST') {
|
|
658
|
+
const chunks: Buffer[] = []
|
|
659
|
+
for await (const chunk of req) {
|
|
660
|
+
chunks.push(chunk as Buffer)
|
|
661
|
+
}
|
|
662
|
+
const body = JSON.parse(Buffer.concat(chunks).toString())
|
|
663
|
+
await transport.handleRequest(req, res, body)
|
|
664
|
+
} else {
|
|
665
|
+
await transport.handleRequest(req, res)
|
|
666
|
+
}
|
|
667
|
+
} else {
|
|
668
|
+
res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' })
|
|
669
|
+
res.end(JSON.stringify({
|
|
670
|
+
jsonrpc: '2.0',
|
|
671
|
+
error: { code: -32004, message: 'Not found' },
|
|
672
|
+
id: null,
|
|
673
|
+
}))
|
|
674
|
+
}
|
|
675
|
+
})
|
|
676
|
+
|
|
677
|
+
await this.mcpServer.connect(transport)
|
|
678
|
+
|
|
679
|
+
await new Promise<void>((resolve) => {
|
|
680
|
+
httpServer.listen(port, () => resolve())
|
|
681
|
+
})
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
private _resolveMCPCompat(explicit?: MCPCompatMode): MCPCompatMode {
|
|
685
|
+
if (explicit === 'codex' || explicit === 'standard') {
|
|
686
|
+
return explicit
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (this.options.mcpCompat === 'codex' || this.options.mcpCompat === 'standard') {
|
|
690
|
+
return this.options.mcpCompat
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const envValue = process.env.MCP_HTTP_COMPAT?.toLowerCase()
|
|
694
|
+
if (envValue === 'codex') {
|
|
695
|
+
return 'codex'
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
return 'standard'
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
private _resolveStdioCompat(explicit?: StdioCompatMode): StdioCompatMode {
|
|
702
|
+
if (explicit === 'codex' || explicit === 'auto' || explicit === 'standard') {
|
|
703
|
+
return explicit
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if (
|
|
707
|
+
this.options.stdioCompat === 'codex'
|
|
708
|
+
|| this.options.stdioCompat === 'auto'
|
|
709
|
+
|| this.options.stdioCompat === 'standard'
|
|
710
|
+
) {
|
|
711
|
+
return this.options.stdioCompat
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const envValue = process.env.MCP_STDIO_COMPAT?.toLowerCase()
|
|
715
|
+
if (envValue === 'codex' || envValue === 'auto') {
|
|
716
|
+
return envValue
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return 'standard'
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
private _normalizeCodexRequest(req: any) {
|
|
723
|
+
if (req.method !== 'POST') return
|
|
724
|
+
|
|
725
|
+
const accept = req.headers.accept
|
|
726
|
+
|
|
727
|
+
if (typeof accept === 'string') {
|
|
728
|
+
if (!accept.includes('application/json')) {
|
|
729
|
+
req.headers.accept = `application/json, ${accept}`
|
|
730
|
+
}
|
|
731
|
+
if (!req.headers.accept.includes('text/event-stream')) {
|
|
732
|
+
req.headers.accept = `${req.headers.accept}, text/event-stream`
|
|
733
|
+
}
|
|
734
|
+
return
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (Array.isArray(accept)) {
|
|
738
|
+
const joined = accept.join(', ')
|
|
739
|
+
req.headers.accept = `${joined}, text/event-stream`
|
|
740
|
+
if (!req.headers.accept.includes('application/json')) {
|
|
741
|
+
req.headers.accept = `application/json, ${req.headers.accept}`
|
|
742
|
+
}
|
|
743
|
+
return
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
req.headers.accept = 'application/json, text/event-stream'
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
private _ensureJSONContentType(res: any) {
|
|
750
|
+
const originalWriteHead = res.writeHead.bind(res)
|
|
751
|
+
|
|
752
|
+
res.writeHead = ((statusCode: number, ...args: any[]) => {
|
|
753
|
+
let statusMessage: string | undefined
|
|
754
|
+
let headers: any
|
|
755
|
+
|
|
756
|
+
if (typeof args[0] === 'string') {
|
|
757
|
+
statusMessage = args[0]
|
|
758
|
+
headers = args[1]
|
|
759
|
+
} else {
|
|
760
|
+
headers = args[0]
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
const hasContentType = (input: any): boolean => {
|
|
764
|
+
if (!input) return false
|
|
765
|
+
|
|
766
|
+
if (Array.isArray(input)) {
|
|
767
|
+
for (let i = 0; i < input.length; i += 2) {
|
|
768
|
+
const key = String(input[i] || '').toLowerCase()
|
|
769
|
+
if (key === 'content-type') return true
|
|
770
|
+
}
|
|
771
|
+
return false
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return Object.keys(input).some((k) => k.toLowerCase() === 'content-type')
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if (headers && !hasContentType(headers)) {
|
|
778
|
+
if (Array.isArray(headers)) {
|
|
779
|
+
headers = [...headers, 'Content-Type', 'application/json; charset=utf-8']
|
|
780
|
+
} else {
|
|
781
|
+
headers = { ...headers, 'Content-Type': 'application/json; charset=utf-8' }
|
|
782
|
+
}
|
|
783
|
+
} else if (!headers && !res.hasHeader('content-type')) {
|
|
784
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8')
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (statusMessage !== undefined && headers !== undefined) {
|
|
788
|
+
return originalWriteHead(statusCode, statusMessage, headers)
|
|
789
|
+
}
|
|
790
|
+
if (statusMessage !== undefined) {
|
|
791
|
+
return originalWriteHead(statusCode, statusMessage)
|
|
792
|
+
}
|
|
793
|
+
if (headers !== undefined) {
|
|
794
|
+
return originalWriteHead(statusCode, headers)
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
return originalWriteHead(statusCode)
|
|
798
|
+
}) as typeof res.writeHead
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
export default MCPServer
|