@sajou/mcp-server 0.6.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.
Files changed (130) hide show
  1. package/README.md +78 -0
  2. package/dist/app.d.ts +32 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +76 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/index.d.ts +18 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +65 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/mcp/transport.d.ts +18 -0
  11. package/dist/mcp/transport.d.ts.map +1 -0
  12. package/dist/mcp/transport.js +56 -0
  13. package/dist/mcp/transport.js.map +1 -0
  14. package/dist/middleware.d.ts +14 -0
  15. package/dist/middleware.d.ts.map +1 -0
  16. package/dist/middleware.js +14 -0
  17. package/dist/middleware.js.map +1 -0
  18. package/dist/routes/discovery.d.ts +8 -0
  19. package/dist/routes/discovery.d.ts.map +1 -0
  20. package/dist/routes/discovery.js +155 -0
  21. package/dist/routes/discovery.js.map +1 -0
  22. package/dist/routes/proxy.d.ts +10 -0
  23. package/dist/routes/proxy.d.ts.map +1 -0
  24. package/dist/routes/proxy.js +84 -0
  25. package/dist/routes/proxy.js.map +1 -0
  26. package/dist/routes/scene.d.ts +10 -0
  27. package/dist/routes/scene.d.ts.map +1 -0
  28. package/dist/routes/scene.js +298 -0
  29. package/dist/routes/scene.js.map +1 -0
  30. package/dist/routes/signals.d.ts +12 -0
  31. package/dist/routes/signals.d.ts.map +1 -0
  32. package/dist/routes/signals.js +61 -0
  33. package/dist/routes/signals.js.map +1 -0
  34. package/dist/routes/tap.d.ts +10 -0
  35. package/dist/routes/tap.d.ts.map +1 -0
  36. package/dist/routes/tap.js +115 -0
  37. package/dist/routes/tap.js.map +1 -0
  38. package/dist/server.d.ts +12 -0
  39. package/dist/server.d.ts.map +1 -0
  40. package/dist/server.js +103 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/state/mutations.d.ts +53 -0
  43. package/dist/state/mutations.d.ts.map +1 -0
  44. package/dist/state/mutations.js +409 -0
  45. package/dist/state/mutations.js.map +1 -0
  46. package/dist/state/store.d.ts +51 -0
  47. package/dist/state/store.d.ts.map +1 -0
  48. package/dist/state/store.js +149 -0
  49. package/dist/state/store.js.map +1 -0
  50. package/dist/tools/create-binding.d.ts +45 -0
  51. package/dist/tools/create-binding.d.ts.map +1 -0
  52. package/dist/tools/create-binding.js +82 -0
  53. package/dist/tools/create-binding.js.map +1 -0
  54. package/dist/tools/create-choreography.d.ts +76 -0
  55. package/dist/tools/create-choreography.d.ts.map +1 -0
  56. package/dist/tools/create-choreography.js +118 -0
  57. package/dist/tools/create-choreography.js.map +1 -0
  58. package/dist/tools/create-shader.d.ts +117 -0
  59. package/dist/tools/create-shader.d.ts.map +1 -0
  60. package/dist/tools/create-shader.js +150 -0
  61. package/dist/tools/create-shader.js.map +1 -0
  62. package/dist/tools/create-sketch.d.ts +96 -0
  63. package/dist/tools/create-sketch.d.ts.map +1 -0
  64. package/dist/tools/create-sketch.js +130 -0
  65. package/dist/tools/create-sketch.js.map +1 -0
  66. package/dist/tools/create-wire.d.ts +32 -0
  67. package/dist/tools/create-wire.d.ts.map +1 -0
  68. package/dist/tools/create-wire.js +84 -0
  69. package/dist/tools/create-wire.js.map +1 -0
  70. package/dist/tools/describe-scene.d.ts +22 -0
  71. package/dist/tools/describe-scene.d.ts.map +1 -0
  72. package/dist/tools/describe-scene.js +194 -0
  73. package/dist/tools/describe-scene.js.map +1 -0
  74. package/dist/tools/emit-signal.d.ts +36 -0
  75. package/dist/tools/emit-signal.d.ts.map +1 -0
  76. package/dist/tools/emit-signal.js +60 -0
  77. package/dist/tools/emit-signal.js.map +1 -0
  78. package/dist/tools/get-catalog.d.ts +27 -0
  79. package/dist/tools/get-catalog.d.ts.map +1 -0
  80. package/dist/tools/get-catalog.js +37 -0
  81. package/dist/tools/get-catalog.js.map +1 -0
  82. package/dist/tools/get-choreographies.d.ts +21 -0
  83. package/dist/tools/get-choreographies.d.ts.map +1 -0
  84. package/dist/tools/get-choreographies.js +70 -0
  85. package/dist/tools/get-choreographies.js.map +1 -0
  86. package/dist/tools/get-scene-state.d.ts +21 -0
  87. package/dist/tools/get-scene-state.d.ts.map +1 -0
  88. package/dist/tools/get-scene-state.js +48 -0
  89. package/dist/tools/get-scene-state.js.map +1 -0
  90. package/dist/tools/get-shaders.d.ts +16 -0
  91. package/dist/tools/get-shaders.d.ts.map +1 -0
  92. package/dist/tools/get-shaders.js +38 -0
  93. package/dist/tools/get-shaders.js.map +1 -0
  94. package/dist/tools/get-sketches.d.ts +16 -0
  95. package/dist/tools/get-sketches.d.ts.map +1 -0
  96. package/dist/tools/get-sketches.js +37 -0
  97. package/dist/tools/get-sketches.js.map +1 -0
  98. package/dist/tools/list-themes.d.ts +21 -0
  99. package/dist/tools/list-themes.d.ts.map +1 -0
  100. package/dist/tools/list-themes.js +32 -0
  101. package/dist/tools/list-themes.js.map +1 -0
  102. package/dist/tools/map-signals.d.ts +30 -0
  103. package/dist/tools/map-signals.d.ts.map +1 -0
  104. package/dist/tools/map-signals.js +44 -0
  105. package/dist/tools/map-signals.js.map +1 -0
  106. package/dist/tools/place-entity.d.ts +47 -0
  107. package/dist/tools/place-entity.d.ts.map +1 -0
  108. package/dist/tools/place-entity.js +85 -0
  109. package/dist/tools/place-entity.js.map +1 -0
  110. package/dist/tools/remove-item.d.ts +25 -0
  111. package/dist/tools/remove-item.d.ts.map +1 -0
  112. package/dist/tools/remove-item.js +55 -0
  113. package/dist/tools/remove-item.js.map +1 -0
  114. package/dist/tools/set-sketch-param.d.ts +29 -0
  115. package/dist/tools/set-sketch-param.d.ts.map +1 -0
  116. package/dist/tools/set-sketch-param.js +49 -0
  117. package/dist/tools/set-sketch-param.js.map +1 -0
  118. package/dist/tools/set-uniform.d.ts +29 -0
  119. package/dist/tools/set-uniform.d.ts.map +1 -0
  120. package/dist/tools/set-uniform.js +49 -0
  121. package/dist/tools/set-uniform.js.map +1 -0
  122. package/dist/tools/update-shader.d.ts +119 -0
  123. package/dist/tools/update-shader.d.ts.map +1 -0
  124. package/dist/tools/update-shader.js +81 -0
  125. package/dist/tools/update-shader.js.map +1 -0
  126. package/dist/tools/update-sketch.d.ts +99 -0
  127. package/dist/tools/update-sketch.d.ts.map +1 -0
  128. package/dist/tools/update-sketch.js +75 -0
  129. package/dist/tools/update-sketch.js.map +1 -0
  130. package/package.json +55 -0
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # @sajou/mcp-server
2
+
3
+ MCP (Model Context Protocol) server for sajou. Lets AI agents interact with the visual choreographer via the standard MCP protocol.
4
+
5
+ ## Setup
6
+
7
+ ### 1. Start the scene-builder dev server
8
+
9
+ ```bash
10
+ pnpm --filter scene-builder dev
11
+ ```
12
+
13
+ The scene-builder runs on `http://localhost:5175` by default.
14
+
15
+ ### 2. Configure your MCP client
16
+
17
+ #### Claude Code
18
+
19
+ Add to your MCP config (`~/.claude/claude_desktop_config.json` or project `.mcp.json`):
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "sajou": {
25
+ "command": "npx",
26
+ "args": ["-y", "@sajou/mcp-server"],
27
+ "env": {
28
+ "SAJOU_DEV_SERVER": "http://localhost:5175"
29
+ }
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ #### Development (from this repo)
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "sajou": {
41
+ "command": "npx",
42
+ "args": ["tsx", "packages/mcp-server/src/index.ts"],
43
+ "env": {
44
+ "SAJOU_DEV_SERVER": "http://localhost:5175"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Tools
52
+
53
+ | Tool | Description |
54
+ |------|-------------|
55
+ | `emit_signal` | Emit a signal to the scene. Triggers choreographies. |
56
+ | `get_scene_state` | Get current scene entities (id, position, visibility). |
57
+ | `get_choreographies` | List available choreographies with descriptions. |
58
+ | `list_themes` | List available themes (citadel, office). |
59
+ | `get_catalog` | Get entity catalog for a theme (buildings, units, etc.). |
60
+ | `map_signals` | Map a signal type to a choreography. |
61
+
62
+ ## Environment variables
63
+
64
+ | Variable | Default | Description |
65
+ |----------|---------|-------------|
66
+ | `SAJOU_DEV_SERVER` | `http://localhost:5175` | URL of the scene-builder dev server |
67
+
68
+ ## Architecture
69
+
70
+ ```
71
+ AI Agent (Claude) ──MCP/stdio──> sajou-mcp ──HTTP──> scene-builder dev server
72
+
73
+ ├── POST /api/signal (emit signals)
74
+ ├── GET /api/scene/state (scene state)
75
+ └── GET /__signals__/stream (SSE)
76
+ ```
77
+
78
+ The MCP server is a thin adapter. It translates MCP tool calls into HTTP requests against the scene-builder's existing API endpoints. The scene-builder handles all signal routing, choreography execution, and rendering.
package/dist/app.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Express application — mounts all route modules.
3
+ *
4
+ * This is the HTTP server for the sajou state server. It provides:
5
+ * - REST API for scene state (read/write)
6
+ * - SSE streams for real-time updates
7
+ * - Signal ingestion endpoint
8
+ * - Local service discovery
9
+ * - CORS proxy for browser clients
10
+ * - Tap hook management
11
+ *
12
+ * Used both as a standalone server (--http flag) and as Express middleware
13
+ * for the botoul deployment (createMcpRouter export).
14
+ */
15
+ import express from "express";
16
+ /** Create the Express app with all routes mounted. */
17
+ export declare function createApp(): express.Express;
18
+ /**
19
+ * Create an Express Router for use as middleware (botoul deployment).
20
+ *
21
+ * Mounts REST routes + MCP Streamable HTTP transport on the router root.
22
+ * When the parent app mounts this on `/mcp`, MCP requests go to `/mcp/`
23
+ * and REST API to `/mcp/api/*`.
24
+ *
25
+ * Usage in botoul's index.js:
26
+ * ```js
27
+ * const { createMcpRouter } = require('./lib/sajou-server.cjs');
28
+ * app.use('/mcp', createMcpRouter());
29
+ * ```
30
+ */
31
+ export declare function createMcpRouter(): express.Router;
32
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAwB9B,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,OAAO,CAAC,OAAO,CAe3C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAAC,MAAM,CAiBhD"}
package/dist/app.js ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Express application — mounts all route modules.
3
+ *
4
+ * This is the HTTP server for the sajou state server. It provides:
5
+ * - REST API for scene state (read/write)
6
+ * - SSE streams for real-time updates
7
+ * - Signal ingestion endpoint
8
+ * - Local service discovery
9
+ * - CORS proxy for browser clients
10
+ * - Tap hook management
11
+ *
12
+ * Used both as a standalone server (--http flag) and as Express middleware
13
+ * for the botoul deployment (createMcpRouter export).
14
+ */
15
+ import express from "express";
16
+ import { createSceneRoutes } from "./routes/scene.js";
17
+ import { createSignalRoutes } from "./routes/signals.js";
18
+ import { createDiscoveryRoutes } from "./routes/discovery.js";
19
+ import { createTapRoutes } from "./routes/tap.js";
20
+ import { createProxyRoutes } from "./routes/proxy.js";
21
+ import { mountMcpTransport } from "./mcp/transport.js";
22
+ import { createServer } from "./server.js";
23
+ /** Simple CORS middleware — allows all origins (dev-friendly). */
24
+ function corsMiddleware(_req, res, next) {
25
+ res.setHeader("Access-Control-Allow-Origin", "*");
26
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
27
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
28
+ res.setHeader("Access-Control-Max-Age", "86400");
29
+ if (_req.method === "OPTIONS") {
30
+ res.status(204).end();
31
+ return;
32
+ }
33
+ next();
34
+ }
35
+ /** Create the Express app with all routes mounted. */
36
+ export function createApp() {
37
+ const app = express();
38
+ // Global middleware
39
+ app.use(corsMiddleware);
40
+ app.use(express.json({ limit: "10mb" }));
41
+ // Mount all route modules
42
+ app.use(createSceneRoutes());
43
+ app.use(createSignalRoutes());
44
+ app.use(createDiscoveryRoutes());
45
+ app.use(createTapRoutes());
46
+ app.use(createProxyRoutes());
47
+ return app;
48
+ }
49
+ /**
50
+ * Create an Express Router for use as middleware (botoul deployment).
51
+ *
52
+ * Mounts REST routes + MCP Streamable HTTP transport on the router root.
53
+ * When the parent app mounts this on `/mcp`, MCP requests go to `/mcp/`
54
+ * and REST API to `/mcp/api/*`.
55
+ *
56
+ * Usage in botoul's index.js:
57
+ * ```js
58
+ * const { createMcpRouter } = require('./lib/sajou-server.cjs');
59
+ * app.use('/mcp', createMcpRouter());
60
+ * ```
61
+ */
62
+ export function createMcpRouter() {
63
+ const router = express.Router();
64
+ router.use(corsMiddleware);
65
+ router.use(express.json({ limit: "10mb" }));
66
+ // REST API routes
67
+ router.use(createSceneRoutes());
68
+ router.use(createSignalRoutes());
69
+ router.use(createDiscoveryRoutes());
70
+ router.use(createTapRoutes());
71
+ router.use(createProxyRoutes());
72
+ // MCP Streamable HTTP — mounted on "/" (router is already prefixed by parent)
73
+ mountMcpTransport(router, createServer, "/");
74
+ return router;
75
+ }
76
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,kEAAkE;AAClE,SAAS,cAAc,CAAC,IAAa,EAAE,GAAa,EAAE,IAAkB;IACtE,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,iCAAiC,CAAC,CAAC;IACjF,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,6BAA6B,CAAC,CAAC;IAC7E,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;IAEjD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IACD,IAAI,EAAE,CAAC;AACT,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IAEtB,oBAAoB;IACpB,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAEzC,0BAA0B;IAC1B,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC7B,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACjC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;IAC3B,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAE7B,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC3B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAE5C,kBAAkB;IAClB,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAEhC,8EAA8E;IAC9E,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC;IAE7C,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sajou server entry point — supports both stdio (MCP) and HTTP modes.
4
+ *
5
+ * Usage:
6
+ * node dist/index.js → stdio transport (default, for Claude Code)
7
+ * node dist/index.js --http → HTTP server on port 3000
8
+ * node dist/index.js --http 8080 → HTTP server on custom port
9
+ *
10
+ * In HTTP mode, the server provides:
11
+ * - REST API on /api/* (same endpoints as the old Vite dev server)
12
+ * - MCP Streamable HTTP on /mcp
13
+ * - SSE streams for real-time updates
14
+ *
15
+ * In stdio mode, the server behaves exactly as before — MCP JSON-RPC over stdin/stdout.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG"}
package/dist/index.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sajou server entry point — supports both stdio (MCP) and HTTP modes.
4
+ *
5
+ * Usage:
6
+ * node dist/index.js → stdio transport (default, for Claude Code)
7
+ * node dist/index.js --http → HTTP server on port 3000
8
+ * node dist/index.js --http 8080 → HTTP server on custom port
9
+ *
10
+ * In HTTP mode, the server provides:
11
+ * - REST API on /api/* (same endpoints as the old Vite dev server)
12
+ * - MCP Streamable HTTP on /mcp
13
+ * - SSE streams for real-time updates
14
+ *
15
+ * In stdio mode, the server behaves exactly as before — MCP JSON-RPC over stdin/stdout.
16
+ */
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import { createServer } from "./server.js";
19
+ import { createApp } from "./app.js";
20
+ import { mountMcpTransport } from "./mcp/transport.js";
21
+ import { cleanupTapHooks } from "./routes/tap.js";
22
+ /** Parse --http flag and optional port from argv. */
23
+ function parseArgs() {
24
+ const args = process.argv.slice(2);
25
+ const httpIndex = args.indexOf("--http");
26
+ if (httpIndex === -1) {
27
+ return { mode: "stdio", port: 3000 };
28
+ }
29
+ const portArg = args[httpIndex + 1];
30
+ const port = portArg && !portArg.startsWith("-") ? parseInt(portArg, 10) : 3000;
31
+ return { mode: "http", port: isNaN(port) ? 3000 : port };
32
+ }
33
+ async function main() {
34
+ const { mode, port } = parseArgs();
35
+ if (mode === "stdio") {
36
+ // Classic stdio mode — MCP JSON-RPC over stdin/stdout
37
+ const server = createServer();
38
+ const transport = new StdioServerTransport();
39
+ await server.connect(transport);
40
+ process.stderr.write("[sajou] Server started (stdio mode)\n");
41
+ }
42
+ else {
43
+ // HTTP mode — Express server with REST + MCP Streamable HTTP
44
+ const app = createApp();
45
+ mountMcpTransport(app, createServer);
46
+ const httpServer = app.listen(port, () => {
47
+ process.stderr.write(`[sajou] Server started on http://localhost:${port}\n`);
48
+ process.stderr.write(`[sajou] REST API: http://localhost:${port}/api/*\n`);
49
+ process.stderr.write(`[sajou] MCP: http://localhost:${port}/mcp\n`);
50
+ });
51
+ // Cleanup on shutdown
52
+ const shutdown = () => {
53
+ cleanupTapHooks();
54
+ httpServer.close();
55
+ process.exit(0);
56
+ };
57
+ process.on("SIGINT", shutdown);
58
+ process.on("SIGTERM", shutdown);
59
+ }
60
+ }
61
+ main().catch((error) => {
62
+ process.stderr.write(`[sajou] Fatal error: ${error instanceof Error ? error.message : String(error)}\n`);
63
+ process.exit(1);
64
+ });
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * MCP Streamable HTTP transport — mounts on /mcp for remote agents.
3
+ *
4
+ * Creates a per-session StreamableHTTPServerTransport and wires it
5
+ * to the same McpServer instance used by stdio. Coexists with the
6
+ * REST routes on the same Express app.
7
+ */
8
+ import type { Router } from "express";
9
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ /**
11
+ * Mount the MCP Streamable HTTP endpoint on an Express router.
12
+ *
13
+ * @param router - Express Router (or app, which extends Router) to mount on
14
+ * @param serverFactory - Factory that creates McpServer instances (one per session)
15
+ * @param path - Route path to mount on (default "/mcp")
16
+ */
17
+ export declare function mountMcpTransport(router: Router, serverFactory: () => McpServer, path?: string): void;
18
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/mcp/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAqB,MAAM,EAAE,MAAM,SAAS,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA8CzE;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,EAAE,IAAI,SAAS,GAAG,IAAI,CAIrG"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * MCP Streamable HTTP transport — mounts on /mcp for remote agents.
3
+ *
4
+ * Creates a per-session StreamableHTTPServerTransport and wires it
5
+ * to the same McpServer instance used by stdio. Coexists with the
6
+ * REST routes on the same Express app.
7
+ */
8
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
9
+ /** Active transports keyed by session ID. */
10
+ const transports = new Map();
11
+ /** Handler for MCP Streamable HTTP requests. */
12
+ async function mcpHandler(req, res, serverFactory) {
13
+ const sessionId = req.headers["mcp-session-id"];
14
+ if (sessionId && transports.has(sessionId)) {
15
+ const transport = transports.get(sessionId);
16
+ await transport.handleRequest(req, res, req.body);
17
+ return;
18
+ }
19
+ if (req.method === "POST") {
20
+ const transport = new StreamableHTTPServerTransport({
21
+ sessionIdGenerator: () => crypto.randomUUID(),
22
+ });
23
+ transport.onclose = () => {
24
+ if (transport.sessionId) {
25
+ transports.delete(transport.sessionId);
26
+ }
27
+ };
28
+ const server = serverFactory();
29
+ await server.connect(transport);
30
+ // handleRequest processes the initialize message and assigns sessionId
31
+ await transport.handleRequest(req, res, req.body);
32
+ // Store AFTER handleRequest so the sessionId is available
33
+ if (transport.sessionId) {
34
+ transports.set(transport.sessionId, transport);
35
+ }
36
+ return;
37
+ }
38
+ res.status(400).json({
39
+ jsonrpc: "2.0",
40
+ error: { code: -32000, message: "No valid session. Send a POST to initialize." },
41
+ id: null,
42
+ });
43
+ }
44
+ /**
45
+ * Mount the MCP Streamable HTTP endpoint on an Express router.
46
+ *
47
+ * @param router - Express Router (or app, which extends Router) to mount on
48
+ * @param serverFactory - Factory that creates McpServer instances (one per session)
49
+ * @param path - Route path to mount on (default "/mcp")
50
+ */
51
+ export function mountMcpTransport(router, serverFactory, path = "/mcp") {
52
+ router.all(path, (req, res) => {
53
+ void mcpHandler(req, res, serverFactory);
54
+ });
55
+ }
56
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/mcp/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAGnG,6CAA6C;AAC7C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAyC,CAAC;AAEpE,gDAAgD;AAChD,KAAK,UAAU,UAAU,CAAC,GAAY,EAAE,GAAa,EAAE,aAA8B;IACnF,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;IAEtE,IAAI,SAAS,IAAI,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC;QAC7C,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAClD,OAAO;IACT,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;YAClD,kBAAkB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE;SAC9C,CAAC,CAAC;QAEH,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;YACvB,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;gBACxB,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACzC,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;QAC/B,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,uEAAuE;QACvE,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAElD,0DAA0D;QAC1D,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;YACxB,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACjD,CAAC;QACD,OAAO;IACT,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,8CAA8C,EAAE;QAChF,EAAE,EAAE,IAAI;KACT,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,aAA8B,EAAE,IAAI,GAAG,MAAM;IAC7F,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QAC/C,KAAK,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Middleware entry point — for CJS bundle used by botoul.
3
+ *
4
+ * Exports `createMcpRouter()` without starting any server.
5
+ * This is the entry point for esbuild when building the botoul bundle.
6
+ *
7
+ * Usage:
8
+ * ```js
9
+ * const { createMcpRouter } = require('./lib/sajou-mcp.cjs');
10
+ * app.use('/mcp', createMcpRouter());
11
+ * ```
12
+ */
13
+ export { createMcpRouter } from "./app.js";
14
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Middleware entry point — for CJS bundle used by botoul.
3
+ *
4
+ * Exports `createMcpRouter()` without starting any server.
5
+ * This is the entry point for esbuild when building the botoul bundle.
6
+ *
7
+ * Usage:
8
+ * ```js
9
+ * const { createMcpRouter } = require('./lib/sajou-mcp.cjs');
10
+ * app.use('/mcp', createMcpRouter());
11
+ * ```
12
+ */
13
+ export { createMcpRouter } from "./app.js";
14
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Local service discovery + OpenClaw token routes.
3
+ *
4
+ * Extracted from localDiscoveryPlugin and openclawTokenPlugin in vite.config.ts.
5
+ */
6
+ import { Router } from "express";
7
+ export declare function createDiscoveryRoutes(): Router;
8
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/routes/discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AA+FjC,wBAAgB,qBAAqB,IAAI,MAAM,CA0F9C"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Local service discovery + OpenClaw token routes.
3
+ *
4
+ * Extracted from localDiscoveryPlugin and openclawTokenPlugin in vite.config.ts.
5
+ */
6
+ import { Router } from "express";
7
+ import { createConnection } from "node:net";
8
+ import { readFile } from "node:fs/promises";
9
+ import { join } from "node:path";
10
+ // ---------------------------------------------------------------------------
11
+ // Probe helpers
12
+ // ---------------------------------------------------------------------------
13
+ /** Probe a TCP port on localhost. Resolves true if something is listening. */
14
+ function tcpProbe(port, timeoutMs = 300) {
15
+ return new Promise((resolve) => {
16
+ const socket = createConnection({ host: "127.0.0.1", port });
17
+ const timer = setTimeout(() => {
18
+ socket.destroy();
19
+ resolve(false);
20
+ }, timeoutMs);
21
+ socket.on("connect", () => {
22
+ clearTimeout(timer);
23
+ socket.destroy();
24
+ resolve(true);
25
+ });
26
+ socket.on("error", () => {
27
+ clearTimeout(timer);
28
+ socket.destroy();
29
+ resolve(false);
30
+ });
31
+ });
32
+ }
33
+ /** Probe an HTTP endpoint. Returns models list on success. */
34
+ async function httpProbe(url, timeoutMs = 300) {
35
+ try {
36
+ const resp = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
37
+ if (!resp.ok)
38
+ return { ok: false };
39
+ const json = (await resp.json());
40
+ const data = json["data"];
41
+ if (Array.isArray(data)) {
42
+ const models = data.map((m) => {
43
+ const entry = m;
44
+ return String(entry["id"] ?? "unknown");
45
+ });
46
+ return { ok: true, models };
47
+ }
48
+ return { ok: true, models: [] };
49
+ }
50
+ catch {
51
+ return { ok: false };
52
+ }
53
+ }
54
+ // ---------------------------------------------------------------------------
55
+ // OpenClaw token reader
56
+ // ---------------------------------------------------------------------------
57
+ const OPENCLAW_CONFIG_PATH = join(process.env["HOME"] ?? process.env["USERPROFILE"] ?? ".", ".openclaw", "openclaw.json");
58
+ async function readOpenClawToken() {
59
+ try {
60
+ const raw = await readFile(OPENCLAW_CONFIG_PATH, "utf8");
61
+ const config = JSON.parse(raw);
62
+ return config.gateway?.auth?.token ?? null;
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Routes
70
+ // ---------------------------------------------------------------------------
71
+ export function createDiscoveryRoutes() {
72
+ const router = Router();
73
+ // GET /api/discover/local — probe known local services
74
+ router.get("/api/discover/local", (_req, res) => {
75
+ Promise.allSettled([
76
+ // Claude Code — always available (SSE internal endpoint)
77
+ Promise.resolve({
78
+ id: "local:claude-code",
79
+ label: "Claude Code",
80
+ protocol: "sse",
81
+ url: "/__signals__/stream",
82
+ available: true,
83
+ models: [],
84
+ }),
85
+ // OpenClaw — TCP probe on 18789
86
+ tcpProbe(18789, 300).then((up) => ({
87
+ id: "local:openclaw",
88
+ label: "OpenClaw",
89
+ protocol: "openclaw",
90
+ url: "ws://127.0.0.1:18789",
91
+ available: up,
92
+ needsApiKey: true,
93
+ models: [],
94
+ })),
95
+ // LM Studio — HTTP probe on 1234
96
+ httpProbe("http://127.0.0.1:1234/v1/models", 300).then((r) => ({
97
+ id: "local:lm-studio",
98
+ label: "LM Studio",
99
+ protocol: "openai",
100
+ url: "http://127.0.0.1:1234",
101
+ available: r.ok,
102
+ needsApiKey: true,
103
+ models: r.models ?? [],
104
+ })),
105
+ // Ollama — HTTP probe on 11434
106
+ httpProbe("http://127.0.0.1:11434/v1/models", 300).then((r) => ({
107
+ id: "local:ollama",
108
+ label: "Ollama",
109
+ protocol: "openai",
110
+ url: "http://127.0.0.1:11434",
111
+ available: r.ok,
112
+ models: r.models ?? [],
113
+ })),
114
+ // Codex — TCP probe on 4500
115
+ tcpProbe(4500, 300).then((up) => ({
116
+ id: "local:codex",
117
+ label: "Codex",
118
+ protocol: "codex",
119
+ url: "ws://127.0.0.1:4500",
120
+ available: up,
121
+ models: [],
122
+ })),
123
+ ]).then((results) => {
124
+ const services = [];
125
+ for (const result of results) {
126
+ if (result.status === "fulfilled") {
127
+ services.push(result.value);
128
+ }
129
+ }
130
+ res.json({ services });
131
+ });
132
+ });
133
+ // GET /api/openclaw/token — serve OpenClaw gateway token (dev only)
134
+ router.get("/api/openclaw/token", (req, res) => {
135
+ const origin = req.headers["origin"] ?? "";
136
+ // In standalone server mode, allow any localhost origin
137
+ if (origin && !origin.includes("localhost") && !origin.includes("127.0.0.1") && !origin.includes("0.0.0.0")) {
138
+ res.status(403).json({ ok: false, error: "Forbidden origin" });
139
+ return;
140
+ }
141
+ readOpenClawToken().then((token) => {
142
+ if (origin) {
143
+ res.setHeader("Access-Control-Allow-Origin", origin);
144
+ }
145
+ if (token) {
146
+ res.json({ ok: true, token });
147
+ }
148
+ else {
149
+ res.json({ ok: false });
150
+ }
151
+ });
152
+ });
153
+ return router;
154
+ }
155
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/routes/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CORS proxy route — forwards requests to external services.
3
+ *
4
+ * Extracted from corsProxyPlugin in vite.config.ts.
5
+ * Used by the browser to bypass CORS restrictions when probing
6
+ * LM Studio, Ollama, and other local services.
7
+ */
8
+ import { Router } from "express";
9
+ export declare function createProxyRoutes(): Router;
10
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/routes/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,wBAAgB,iBAAiB,IAAI,MAAM,CA+E1C"}