nomos-mcp-bridge 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 nomos system
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # nomos MCP Bridge
2
+
3
+ A local MCP proxy that manages connections to one or more [nomos system](https://nomos-system.com) controllers. Instead of configuring each controller individually in your AI client, the bridge lets you register multiple controllers and switch between them via natural language.
4
+
5
+ Works with any MCP-compatible AI client — Claude Desktop, Cursor, Windsurf, ChatGPT Desktop, and more.
6
+
7
+ ## How It Works
8
+
9
+ ```
10
+ MCP Client ──stdio──► nomos-mcp-bridge ──Streamable HTTP──► nomos Controller A
11
+ (local proxy) ──Streamable HTTP──► nomos Controller B
12
+ ──Streamable HTTP──► nomos Controller C
13
+ ```
14
+
15
+ The bridge runs as a local MCP server (via stdio) and connects to nomos controllers over the network using the MCP Streamable HTTP transport. All tools, resources, and prompts from the connected controller are dynamically proxied — the bridge stays lightweight and always exposes exactly the capabilities the controller supports.
16
+
17
+ ## Prerequisites
18
+
19
+ - **Node.js** 18 or later
20
+ - A **nomos system controller** with MCP enabled (Skills > MCP) and a configured token
21
+ - **Network access** to the controller from your machine
22
+
23
+ ## MCP Client Configuration
24
+
25
+ The bridge works with any AI client that supports the [Model Context Protocol](https://modelcontextprotocol.io). No manual installation needed — just add the config and your client will run the bridge automatically via `npx`.
26
+
27
+ ### Claude Desktop
28
+
29
+ Add to your `claude_desktop_config.json`:
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "nomos": {
35
+ "command": "npx",
36
+ "args": ["-y", "nomos-mcp-bridge"]
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### Cursor
43
+
44
+ Add to your Cursor MCP settings (`.cursor/mcp.json`):
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "nomos": {
50
+ "command": "npx",
51
+ "args": ["-y", "nomos-mcp-bridge"]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### Windsurf
58
+
59
+ Add to your Windsurf MCP config (`~/.codeium/windsurf/mcp_config.json`):
60
+
61
+ ```json
62
+ {
63
+ "mcpServers": {
64
+ "nomos": {
65
+ "command": "npx",
66
+ "args": ["-y", "nomos-mcp-bridge"]
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### Claude Code (CLI)
73
+
74
+ ```bash
75
+ claude mcp add nomos -- npx -y nomos-mcp-bridge
76
+ ```
77
+
78
+ ### Other MCP Clients
79
+
80
+ Any client supporting stdio-based MCP servers can use the bridge. The command is:
81
+
82
+ ```
83
+ npx -y nomos-mcp-bridge
84
+ ```
85
+
86
+ ## Adding Controllers
87
+
88
+ ### Option 1: Via the Setup Web Page
89
+
90
+ Tell your AI assistant to **open the setup page**:
91
+
92
+ > "Open the nomos setup page"
93
+
94
+ This opens a local web UI in your browser where you can enter the controller name, URL, and MCP token.
95
+
96
+ ### Option 2: Via AI Chat
97
+
98
+ Tell your AI assistant to add a controller:
99
+
100
+ > "Add my nomos controller 'Wohnhaus' at 192.168.1.100 with token abc123"
101
+
102
+ The assistant will use the `add_controller` tool to register it.
103
+
104
+ ### Option 3: Manually
105
+
106
+ Edit `~/.config/nomos-mcp/controllers.json`:
107
+
108
+ ```json
109
+ {
110
+ "controllers": [
111
+ {
112
+ "id": "some-uuid",
113
+ "name": "Wohnhaus",
114
+ "url": "https://192.168.1.100/mcp",
115
+ "token": "your-mcp-token"
116
+ }
117
+ ],
118
+ "activeControllerId": "some-uuid"
119
+ }
120
+ ```
121
+
122
+ ## Usage
123
+
124
+ Once controllers are registered, simply tell your AI assistant which one to use:
125
+
126
+ > "Connect to controller Wohnhaus"
127
+
128
+ > "Switch to Büro controller"
129
+
130
+ > "Show me all my controllers"
131
+
132
+ After connecting, all nomos tools are available as if the client were directly connected to the controller. You can:
133
+
134
+ - Control devices ("Turn off the living room lights")
135
+ - Create scenes and automations
136
+ - Check system status
137
+ - Configure the smart home
138
+
139
+ ## Bridge Tools
140
+
141
+ The bridge provides these management tools:
142
+
143
+ | Tool | Description |
144
+ |------|-------------|
145
+ | `list_controllers` | List all registered controllers |
146
+ | `select_controller` | Connect to a controller by name |
147
+ | `add_controller` | Register a new controller |
148
+ | `remove_controller` | Remove a registered controller |
149
+ | `open_setup` | Open the setup web page in the browser |
150
+ | `connection_status` | Show current connection status |
151
+
152
+ ## Configuration
153
+
154
+ Controller credentials are stored in `~/.config/nomos-mcp/controllers.json`. The setup web server runs on `http://localhost:18900` (auto-increments if the port is in use).
155
+
156
+ ## Security Notes
157
+
158
+ - Tokens are stored in plain text in the config file. Ensure appropriate file permissions.
159
+ - The setup web server only listens on `127.0.0.1` (localhost) and is not accessible from the network.
160
+ - nomos controllers use HTTPS with self-signed certificates by default. Node.js may reject these — set `NODE_TLS_REJECT_UNAUTHORIZED=0` in your MCP client config if needed:
161
+
162
+ ```json
163
+ {
164
+ "mcpServers": {
165
+ "nomos": {
166
+ "command": "npx",
167
+ "args": ["-y", "nomos-mcp-bridge"],
168
+ "env": {
169
+ "NODE_TLS_REJECT_UNAUTHORIZED": "0"
170
+ }
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ ## Development
177
+
178
+ ```bash
179
+ # Clone the repository
180
+ git clone https://github.com/nomos-system/nomos-mcp-bridge.git
181
+ cd nomos-mcp-bridge
182
+
183
+ # Install dependencies and build
184
+ npm install
185
+ npm run build
186
+
187
+ # Run
188
+ npm run start
189
+
190
+ # Or build and run in one step
191
+ npm run dev
192
+ ```
193
+
194
+ ## License
195
+
196
+ MIT
@@ -0,0 +1,13 @@
1
+ interface ViewMessage {
2
+ type: 'error' | 'success';
3
+ text: string;
4
+ }
5
+ interface ViewControllerEntry {
6
+ name: string;
7
+ url: string;
8
+ isActive: boolean;
9
+ }
10
+ export declare function setupPage(controllers: ViewControllerEntry[], message?: ViewMessage | null): string;
11
+ export declare function successPage(controllerName: string): string;
12
+ export {};
13
+ //# sourceMappingURL=pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/auth/pages.ts"],"names":[],"mappings":"AAAA,UAAU,WAAW;IACjB,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,mBAAmB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;CACrB;AA8CD,wBAAgB,SAAS,CAAC,WAAW,EAAE,mBAAmB,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAqClG;AAED,wBAAgB,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAO1D"}
@@ -0,0 +1,86 @@
1
+ function escapeHtml(str) {
2
+ return String(str)
3
+ .replace(/&/g, '&')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;');
7
+ }
8
+ function layout(title, body) {
9
+ return '<!DOCTYPE html>'
10
+ + '<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">'
11
+ + '<title>' + title + ' — nomos MCP Bridge</title>'
12
+ + '<style>'
13
+ + ':root{--bg:#0f1117;--card:#1a1d27;--border:#2a2d3a;--accent:#4f8ff7;--accent-hover:#3a7ae0;--text:#e4e4e7;--muted:#9ca3af;--danger:#ef4444;--success:#22c55e}'
14
+ + '*{margin:0;padding:0;box-sizing:border-box}'
15
+ + 'body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}'
16
+ + '.container{width:100%;max-width:480px}'
17
+ + '.card{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:32px}'
18
+ + '.logo{text-align:center;margin-bottom:24px;font-size:28px;font-weight:700;letter-spacing:-0.5px}'
19
+ + '.logo span{color:var(--accent)}'
20
+ + 'h2{font-size:18px;margin-bottom:16px;font-weight:600}'
21
+ + 'p{color:var(--muted);font-size:14px;line-height:1.5;margin-bottom:16px}'
22
+ + 'label{display:block;font-size:13px;font-weight:500;margin-bottom:6px;color:var(--muted)}'
23
+ + 'input[type="text"],input[type="url"],input[type="password"]{width:100%;padding:10px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;outline:none;transition:border-color .2s}'
24
+ + 'input:focus{border-color:var(--accent)}'
25
+ + '.field{margin-bottom:16px}'
26
+ + '.btn{display:inline-block;width:100%;padding:10px 16px;background:var(--accent);color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;transition:background .2s;text-align:center}'
27
+ + '.btn:hover{background:var(--accent-hover)}'
28
+ + '.status{padding:12px 16px;border-radius:8px;font-size:14px;margin-bottom:16px}'
29
+ + '.status-success{background:#052e16;border:1px solid #166534;color:var(--success)}'
30
+ + '.status-error{background:#2c0b0e;border:1px solid #7f1d1d;color:var(--danger)}'
31
+ + '.controllers{list-style:none;margin-bottom:16px}'
32
+ + '.controllers li{padding:12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;margin-bottom:8px;display:flex;justify-content:space-between;align-items:center}'
33
+ + '.controllers li .name{font-weight:600}'
34
+ + '.controllers li .url{font-size:12px;color:var(--muted)}'
35
+ + '.controllers li .active{font-size:11px;color:var(--success);font-weight:600;text-transform:uppercase}'
36
+ + '.hint{font-size:12px;color:var(--muted);margin-top:4px}'
37
+ + '</style></head><body>'
38
+ + '<div class="container">'
39
+ + '<div class="logo"><span>nomos</span> MCP Bridge</div>'
40
+ + body
41
+ + '</div></body></html>';
42
+ }
43
+ export function setupPage(controllers, message) {
44
+ let statusHtml = '';
45
+ if (message) {
46
+ const cssClass = message.type === 'error' ? 'status-error' : 'status-success';
47
+ statusHtml = '<div class="status ' + cssClass + '">' + escapeHtml(message.text) + '</div>';
48
+ }
49
+ let listHtml = '';
50
+ if (controllers.length > 0) {
51
+ listHtml = '<h2>Registered Controllers</h2><ul class="controllers">';
52
+ for (const c of controllers) {
53
+ listHtml += '<li><div><div class="name">' + escapeHtml(c.name) + '</div>'
54
+ + '<div class="url">' + escapeHtml(c.url) + '</div></div>'
55
+ + (c.isActive ? '<div class="active">Active</div>' : '')
56
+ + '</li>';
57
+ }
58
+ listHtml += '</ul>';
59
+ }
60
+ const body = '<div class="card">'
61
+ + statusHtml
62
+ + listHtml
63
+ + '<h2>Add Controller</h2>'
64
+ + '<p>Enter the connection details for your nomos system controller. You can find the MCP token in the nomos system configuration under Settings &gt; MCP.</p>'
65
+ + '<form method="POST" action="/add">'
66
+ + '<div class="field"><label for="name">Name</label>'
67
+ + '<input type="text" id="name" name="name" placeholder="e.g. Wohnhaus" required>'
68
+ + '<div class="hint">A friendly name to identify this controller.</div></div>'
69
+ + '<div class="field"><label for="url">Controller URL</label>'
70
+ + '<input type="url" id="url" name="url" placeholder="https://192.168.1.100" required>'
71
+ + '<div class="hint">The IP address or hostname of your nomos system controller (without /mcp path).</div></div>'
72
+ + '<div class="field"><label for="token">MCP Token</label>'
73
+ + '<input type="password" id="token" name="token" placeholder="Bearer token" required></div>'
74
+ + '<button type="submit" class="btn">Add Controller</button>'
75
+ + '</form></div>';
76
+ return layout('Setup', body);
77
+ }
78
+ export function successPage(controllerName) {
79
+ const body = '<div class="card">'
80
+ + '<div class="status status-success">Controller "' + escapeHtml(controllerName) + '" has been added successfully.</div>'
81
+ + '<p>You can now close this window and use the controller via Claude. Tell Claude to <strong>select_controller</strong> with the name "' + escapeHtml(controllerName) + '".</p>'
82
+ + '<p style="margin-top:16px"><a href="/" class="btn">Add another controller</a></p>'
83
+ + '</div>';
84
+ return layout('Success', body);
85
+ }
86
+ //# sourceMappingURL=pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/auth/pages.ts"],"names":[],"mappings":"AAWA,SAAS,UAAU,CAAC,GAAW;IAC3B,OAAO,MAAM,CAAC,GAAG,CAAC;SACb,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,IAAY;IACvC,OAAO,iBAAiB;UAClB,mHAAmH;UACnH,SAAS,GAAG,KAAK,GAAG,6BAA6B;UACjD,SAAS;UACT,+JAA+J;UAC/J,6CAA6C;UAC7C,6MAA6M;UAC7M,wCAAwC;UACxC,8FAA8F;UAC9F,kGAAkG;UAClG,iCAAiC;UACjC,uDAAuD;UACvD,yEAAyE;UACzE,0FAA0F;UAC1F,2OAA2O;UAC3O,yCAAyC;UACzC,4BAA4B;UAC5B,qNAAqN;UACrN,4CAA4C;UAC5C,gFAAgF;UAChF,mFAAmF;UACnF,gFAAgF;UAChF,kDAAkD;UAClD,qLAAqL;UACrL,wCAAwC;UACxC,yDAAyD;UACzD,uGAAuG;UACvG,yDAAyD;UACzD,uBAAuB;UACvB,yBAAyB;UACzB,uDAAuD;UACvD,IAAI;UACJ,sBAAsB,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,WAAkC,EAAE,OAA4B;IACtF,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,OAAO,EAAE,CAAC;QACV,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAAC;QAC9E,UAAU,GAAG,qBAAqB,GAAG,QAAQ,GAAG,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;IAC/F,CAAC;IAED,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,QAAQ,GAAG,yDAAyD,CAAC;QACrE,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC1B,QAAQ,IAAI,6BAA6B,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ;kBACnE,mBAAmB,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,cAAc;kBACxD,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,EAAE,CAAC;kBACtD,OAAO,CAAC;QAClB,CAAC;QACD,QAAQ,IAAI,OAAO,CAAC;IACxB,CAAC;IAED,MAAM,IAAI,GAAG,oBAAoB;UAC3B,UAAU;UACV,QAAQ;UACR,yBAAyB;UACzB,6JAA6J;UAC7J,oCAAoC;UACpC,mDAAmD;UACnD,gFAAgF;UAChF,4EAA4E;UAC5E,4DAA4D;UAC5D,qFAAqF;UACrF,+GAA+G;UAC/G,yDAAyD;UACzD,2FAA2F;UAC3F,2DAA2D;UAC3D,eAAe,CAAC;IAEtB,OAAO,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,cAAsB;IAC9C,MAAM,IAAI,GAAG,oBAAoB;UAC3B,iDAAiD,GAAG,UAAU,CAAC,cAAc,CAAC,GAAG,sCAAsC;UACvH,uIAAuI,GAAG,UAAU,CAAC,cAAc,CAAC,GAAG,QAAQ;UAC/K,mFAAmF;UACnF,QAAQ,CAAC;IACf,OAAO,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function getAuthUrl(): string;
2
+ export declare function getAuthPort(): number;
3
+ export declare function start(): Promise<string>;
4
+ export declare function stop(): Promise<void>;
5
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/auth/server.ts"],"names":[],"mappings":"AAOA,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAsBvC;AAED,wBAAgB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAWpC"}
@@ -0,0 +1,102 @@
1
+ import http from 'http';
2
+ import * as config from '../config.js';
3
+ import { setupPage, successPage } from './pages.js';
4
+ let authPort = 18900;
5
+ let authServer = null;
6
+ export function getAuthUrl() {
7
+ return 'http://localhost:' + authPort;
8
+ }
9
+ export function getAuthPort() {
10
+ return authPort;
11
+ }
12
+ export function start() {
13
+ return new Promise((resolve, reject) => {
14
+ if (authServer) {
15
+ resolve(getAuthUrl());
16
+ return;
17
+ }
18
+ authServer = http.createServer(handleRequest);
19
+ authServer.on('error', (err) => {
20
+ if (err.code === 'EADDRINUSE') {
21
+ authPort++;
22
+ authServer.listen(authPort, '127.0.0.1');
23
+ }
24
+ else {
25
+ reject(err);
26
+ }
27
+ });
28
+ authServer.listen(authPort, '127.0.0.1', () => {
29
+ resolve(getAuthUrl());
30
+ });
31
+ });
32
+ }
33
+ export function stop() {
34
+ return new Promise(resolve => {
35
+ if (authServer) {
36
+ authServer.close(() => {
37
+ authServer = null;
38
+ resolve();
39
+ });
40
+ }
41
+ else {
42
+ resolve();
43
+ }
44
+ });
45
+ }
46
+ function handleRequest(req, res) {
47
+ const parsedUrl = new URL(req.url ?? '/', 'http://localhost');
48
+ if (req.method === 'GET' && parsedUrl.pathname === '/') {
49
+ serveSetupPage(res, null);
50
+ return;
51
+ }
52
+ if (req.method === 'POST' && parsedUrl.pathname === '/add') {
53
+ handleAddController(req, res);
54
+ return;
55
+ }
56
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
57
+ res.end('Not Found');
58
+ }
59
+ function serveSetupPage(res, message) {
60
+ const controllers = config.getControllers();
61
+ const activeId = config.getActiveControllerId();
62
+ const viewControllers = controllers.map(c => ({
63
+ name: c.name,
64
+ url: c.url,
65
+ isActive: c.id === activeId,
66
+ }));
67
+ const html = setupPage(viewControllers, message);
68
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
69
+ res.end(html);
70
+ }
71
+ function handleAddController(req, res) {
72
+ let body = '';
73
+ req.on('data', (chunk) => {
74
+ body += chunk.toString();
75
+ });
76
+ req.on('end', () => {
77
+ const params = new URLSearchParams(body);
78
+ const name = (params.get('name') ?? '').trim();
79
+ let url = (params.get('url') ?? '').trim();
80
+ const token = (params.get('token') ?? '').trim();
81
+ if (!name || !url || !token) {
82
+ serveSetupPage(res, { type: 'error', text: 'All fields are required.' });
83
+ return;
84
+ }
85
+ // Normalize URL: strip trailing slash, append /mcp if missing
86
+ url = url.replace(/\/+$/, '');
87
+ if (!url.endsWith('/mcp')) {
88
+ url += '/mcp';
89
+ }
90
+ try {
91
+ const entry = config.addController({ name, url, token });
92
+ const html = successPage(entry.name);
93
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
94
+ res.end(html);
95
+ }
96
+ catch (e) {
97
+ const message = e instanceof Error ? e.message : String(e);
98
+ serveSetupPage(res, { type: 'error', text: message });
99
+ }
100
+ });
101
+ }
102
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/auth/server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEpD,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrB,IAAI,UAAU,GAAuB,IAAI,CAAC;AAE1C,MAAM,UAAU,UAAU;IACtB,OAAO,mBAAmB,GAAG,QAAQ,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,WAAW;IACvB,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,KAAK;IACjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,IAAI,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;YACtB,OAAO;QACX,CAAC;QAED,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QAE9C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAClD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC5B,QAAQ,EAAE,CAAC;gBACX,UAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YAC9C,CAAC;iBAAM,CAAC;gBACJ,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE;YAC1C,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,IAAI;IAChB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QACzB,IAAI,UAAU,EAAE,CAAC;YACb,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE;gBAClB,UAAU,GAAG,IAAI,CAAC;gBAClB,OAAO,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,aAAa,CAAC,GAAyB,EAAE,GAAwB;IACtE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;IAE9D,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,SAAS,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;QACrD,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1B,OAAO;IACX,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,SAAS,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACzD,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC9B,OAAO;IACX,CAAC;IAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;IACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,GAAwB,EAAE,OAA2D;IACzG,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC;IAChD,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,QAAQ;KAC9B,CAAC,CAAC,CAAC;IACJ,MAAM,IAAI,GAAG,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IACjD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;IACnE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAyB,EAAE,GAAwB;IAC5E,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;QAC7B,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;QACf,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAEjD,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,cAAc,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC,CAAC;YACzE,OAAO;QACX,CAAC;QAED,8DAA8D;QAC9D,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,GAAG,IAAI,MAAM,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;YACzD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;YACnE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,CAAU,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC3D,cAAc,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1D,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface Controller {
2
+ id: string;
3
+ name: string;
4
+ url: string;
5
+ token: string;
6
+ }
7
+ export interface BridgeConfig {
8
+ controllers: Controller[];
9
+ activeControllerId: string | null;
10
+ }
11
+ export declare const CONFIG_DIR: string;
12
+ export declare const CONFIG_FILE: string;
13
+ export declare function load(): BridgeConfig;
14
+ export declare function save(config: BridgeConfig): void;
15
+ export declare function getControllers(): Controller[];
16
+ export declare function getController(id: string): Controller | null;
17
+ export declare function getControllerByName(name: string): Controller | null;
18
+ export declare function addController(controller: {
19
+ name: string;
20
+ url: string;
21
+ token: string;
22
+ }): Controller;
23
+ export declare function updateController(id: string, updates: Partial<Omit<Controller, 'id'>>): Controller;
24
+ export declare function removeController(id: string): Controller;
25
+ export declare function getActiveControllerId(): string | null;
26
+ export declare function setActiveControllerId(id: string | null): void;
27
+ export declare function getActiveController(): Controller | null;
28
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,eAAO,MAAM,UAAU,QAAkD,CAAC;AAC1E,eAAO,MAAM,WAAW,QAA4C,CAAC;AAQrE,wBAAgB,IAAI,IAAI,YAAY,CAQnC;AAED,wBAAgB,IAAI,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAG/C;AAED,wBAAgB,cAAc,IAAI,UAAU,EAAE,CAE7C;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAG3D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAInE;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CAyBlG;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,GAAG,UAAU,CAWjG;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAYvD;AAED,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAU7D;AAED,wBAAgB,mBAAmB,IAAI,UAAU,GAAG,IAAI,CAIvD"}
package/dist/config.js ADDED
@@ -0,0 +1,106 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import crypto from 'crypto';
5
+ export const CONFIG_DIR = path.join(os.homedir(), '.config', 'nomos-mcp');
6
+ export const CONFIG_FILE = path.join(CONFIG_DIR, 'controllers.json');
7
+ function ensureConfigDir() {
8
+ if (!fs.existsSync(CONFIG_DIR)) {
9
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
10
+ }
11
+ }
12
+ export function load() {
13
+ ensureConfigDir();
14
+ try {
15
+ const data = fs.readFileSync(CONFIG_FILE, 'utf8');
16
+ return JSON.parse(data);
17
+ }
18
+ catch {
19
+ return { controllers: [], activeControllerId: null };
20
+ }
21
+ }
22
+ export function save(config) {
23
+ ensureConfigDir();
24
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
25
+ }
26
+ export function getControllers() {
27
+ return load().controllers;
28
+ }
29
+ export function getController(id) {
30
+ const config = load();
31
+ return config.controllers.find(c => c.id === id) ?? null;
32
+ }
33
+ export function getControllerByName(name) {
34
+ const config = load();
35
+ const lower = name.toLowerCase();
36
+ return config.controllers.find(c => c.name.toLowerCase() === lower) ?? null;
37
+ }
38
+ export function addController(controller) {
39
+ const config = load();
40
+ const existing = config.controllers.find(c => c.name.toLowerCase() === controller.name.toLowerCase());
41
+ if (existing) {
42
+ throw new Error(`A controller with the name "${controller.name}" already exists.`);
43
+ }
44
+ const entry = {
45
+ id: crypto.randomUUID(),
46
+ name: controller.name,
47
+ url: controller.url,
48
+ token: controller.token,
49
+ };
50
+ config.controllers.push(entry);
51
+ // Auto-select if this is the only controller
52
+ if (config.controllers.length === 1) {
53
+ config.activeControllerId = entry.id;
54
+ }
55
+ save(config);
56
+ return entry;
57
+ }
58
+ export function updateController(id, updates) {
59
+ const config = load();
60
+ const controller = config.controllers.find(c => c.id === id);
61
+ if (!controller) {
62
+ throw new Error('Controller not found: ' + id);
63
+ }
64
+ if (updates.name !== undefined)
65
+ controller.name = updates.name;
66
+ if (updates.url !== undefined)
67
+ controller.url = updates.url;
68
+ if (updates.token !== undefined)
69
+ controller.token = updates.token;
70
+ save(config);
71
+ return controller;
72
+ }
73
+ export function removeController(id) {
74
+ const config = load();
75
+ const index = config.controllers.findIndex(c => c.id === id);
76
+ if (index === -1) {
77
+ throw new Error('Controller not found: ' + id);
78
+ }
79
+ const removed = config.controllers.splice(index, 1)[0];
80
+ if (config.activeControllerId === id) {
81
+ config.activeControllerId = config.controllers.length > 0 ? config.controllers[0].id : null;
82
+ }
83
+ save(config);
84
+ return removed;
85
+ }
86
+ export function getActiveControllerId() {
87
+ return load().activeControllerId;
88
+ }
89
+ export function setActiveControllerId(id) {
90
+ const config = load();
91
+ if (id !== null) {
92
+ const exists = config.controllers.some(c => c.id === id);
93
+ if (!exists) {
94
+ throw new Error('Controller not found: ' + id);
95
+ }
96
+ }
97
+ config.activeControllerId = id;
98
+ save(config);
99
+ }
100
+ export function getActiveController() {
101
+ const config = load();
102
+ if (!config.activeControllerId)
103
+ return null;
104
+ return config.controllers.find(c => c.id === config.activeControllerId) ?? null;
105
+ }
106
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}