@noraai/mcp-server
Advanced tools
+1
-1
| { | ||
| "name": "@noraai/mcp-server", | ||
| "version": "0.1.2", | ||
| "version": "0.1.3", | ||
| "description": "MCP server for Nora — deploy, monitor, and operate self-hosted OpenClaw and Hermes agent fleets on Docker or Kubernetes.", | ||
@@ -5,0 +5,0 @@ "mcpName": "io.github.solomon2773/nora", |
+22
-0
@@ -29,2 +29,16 @@ # @noraai/mcp-server | ||
| ### Docker | ||
| Build the same stdio server as a non-root container: | ||
| ```bash | ||
| docker build -t nora-mcp ./mcp-server | ||
| docker run --rm -i \ | ||
| -e NORA_API_URL=https://nora.example.com \ | ||
| -e NORA_API_KEY=nora_xxxxxxxx \ | ||
| nora-mcp | ||
| ``` | ||
| MCP clients should keep stdin open and pass secrets through environment variables; the image does not persist credentials or other state. | ||
| ## Auth | ||
@@ -49,4 +63,12 @@ | ||
| ## Privacy Policy | ||
| The Nora MCP connector runs locally and does not collect telemetry or persist credentials, tool inputs, or API responses. It sends each tool request and the configured API key directly to the Nora deployment identified by `NORA_API_URL`; no separate connector service or advertising network receives that data. | ||
| The connector retains no data after its process exits. Your Nora operator controls the storage and retention of account, agent, log, metric, and integration data in that deployment, and connected providers may apply their own policies when Nora invokes them. See the full [Nora Privacy Policy](https://nora.solomontsao.com/privacy) or contact [privacy@solomontsao.com](mailto:privacy@solomontsao.com). | ||
| If Nora is useful to you, a ⭐ on the [GitHub repo](https://github.com/solomon2773/nora) helps other self-hosters find it. | ||
| ## License | ||
| Apache-2.0 |
+1
-1
@@ -41,3 +41,3 @@ // Thin wrapper around the Nora public REST API, mirroring cli/src/client.js. | ||
| Authorization: `Bearer ${resolved.apiKey}`, | ||
| "User-Agent": "nora-mcp-server/0.1.0", | ||
| "User-Agent": "nora-mcp-server/0.1.3", | ||
| }, | ||
@@ -44,0 +44,0 @@ body: body !== undefined ? JSON.stringify(body) : undefined, |
+18
-4
@@ -7,3 +7,4 @@ #!/usr/bin/env node | ||
| import { pathToFileURL } from "node:url"; | ||
| import fs from "node:fs"; | ||
| import { fileURLToPath } from "node:url"; | ||
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
@@ -15,3 +16,3 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | ||
| export const SERVER_INFO = { name: "nora", version: "0.1.2" }; | ||
| export const SERVER_INFO = { name: "nora", version: "0.1.3" }; | ||
@@ -43,4 +44,17 @@ export function createServer({ api, env = process.env } = {}) { | ||
| const isDirectRun = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href; | ||
| if (isDirectRun) { | ||
| function isDirectRun() { | ||
| const entrypointPath = process.argv[1]; | ||
| const modulePath = fileURLToPath(import.meta.url); | ||
| if (!entrypointPath || !fs.existsSync(entrypointPath) || !fs.existsSync(modulePath)) { | ||
| return false; | ||
| } | ||
| try { | ||
| return fs.realpathSync(entrypointPath) === fs.realpathSync(modulePath); | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
| if (isDirectRun()) { | ||
| main().catch((error) => { | ||
@@ -47,0 +61,0 @@ console.error(error); |
32646
4.85%452
2.73%73
43.14%5
25%