@niroai/mcp-server 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.
Files changed (2) hide show
  1. package/index.js +185 -0
  2. package/package.json +32 -0
package/index.js ADDED
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Niro MCP Server — stdio-to-SSE bridge.
5
+ *
6
+ * Reads MCP JSON-RPC messages from stdin, forwards them to the
7
+ * Niro ai-assistant SSE transport, and writes responses to stdout.
8
+ *
9
+ * Required env vars:
10
+ * NIRO_API_KEY — Your Niro API key (from console.niroai.dev)
11
+ * NIRO_PROJECT_ID — Project ID to query
12
+ * NIRO_API_URL — API base URL (https://api.niroai.dev or http://localhost:8098)
13
+ */
14
+
15
+ const http = require("http");
16
+ const https = require("https");
17
+ const readline = require("readline");
18
+
19
+ const API_KEY = process.env.NIRO_API_KEY;
20
+ const PROJECT_ID = process.env.NIRO_PROJECT_ID;
21
+ const API_URL = process.env.NIRO_API_URL || "https://api.niroai.dev";
22
+
23
+ function fatal(message) {
24
+ const error = {
25
+ jsonrpc: "2.0",
26
+ id: null,
27
+ error: { code: -32603, message },
28
+ };
29
+ process.stdout.write(JSON.stringify(error) + "\n");
30
+ process.stderr.write(`[niro-mcp] ERROR: ${message}\n`);
31
+ process.exit(1);
32
+ }
33
+
34
+ if (!API_KEY) fatal("NIRO_API_KEY is required. Get it from console.niroai.dev > Settings > Account.");
35
+ if (!PROJECT_ID) fatal("NIRO_PROJECT_ID is required. Find it on the Projects page at console.niroai.dev.");
36
+
37
+ const parsedUrl = new URL(API_URL);
38
+ const httpModule = parsedUrl.protocol === "https:" ? https : http;
39
+
40
+ let sessionId = null;
41
+
42
+ /**
43
+ * Connect to the SSE endpoint and listen for responses.
44
+ */
45
+ function connectSse() {
46
+ return new Promise((resolve, reject) => {
47
+ const sseUrl = `${API_URL}/mcp/sse`;
48
+ process.stderr.write(`[niro-mcp] Connecting to ${sseUrl}\n`);
49
+
50
+ const req = httpModule.get(sseUrl, {
51
+ headers: { "Accept": "text/event-stream" },
52
+ }, (res) => {
53
+ if (res.statusCode !== 200) {
54
+ reject(new Error(`SSE connection failed: HTTP ${res.statusCode}`));
55
+ return;
56
+ }
57
+
58
+ let buffer = "";
59
+
60
+ res.on("data", (chunk) => {
61
+ buffer += chunk.toString();
62
+ const lines = buffer.split("\n");
63
+ buffer = lines.pop(); // Keep incomplete line in buffer
64
+
65
+ let eventName = null;
66
+ for (const line of lines) {
67
+ if (line.startsWith("event:")) {
68
+ eventName = line.slice(6).trim();
69
+ } else if (line.startsWith("data:")) {
70
+ const data = line.slice(5).trim();
71
+
72
+ if (eventName === "endpoint") {
73
+ // First event: receive the message endpoint URL with sessionId
74
+ const match = data.match(/sessionId=([a-f0-9-]+)/);
75
+ if (match) {
76
+ sessionId = match[1];
77
+ process.stderr.write(`[niro-mcp] Session established: ${sessionId}\n`);
78
+ resolve();
79
+ }
80
+ } else if (eventName === "message") {
81
+ // Response from the server — write to stdout
82
+ process.stdout.write(data + "\n");
83
+ }
84
+ eventName = null;
85
+ }
86
+ }
87
+ });
88
+
89
+ res.on("error", (err) => {
90
+ process.stderr.write(`[niro-mcp] SSE error: ${err.message}\n`);
91
+ });
92
+
93
+ res.on("end", () => {
94
+ process.stderr.write("[niro-mcp] SSE connection closed\n");
95
+ process.exit(0);
96
+ });
97
+ });
98
+
99
+ req.on("error", (err) => {
100
+ reject(new Error(`Failed to connect to ${sseUrl}: ${err.message}`));
101
+ });
102
+ });
103
+ }
104
+
105
+ /**
106
+ * Send a JSON-RPC message to the server via HTTP POST.
107
+ */
108
+ function sendMessage(message) {
109
+ return new Promise((resolve, reject) => {
110
+ const url = `${API_URL}/mcp/messages?sessionId=${sessionId}`;
111
+ const postData = JSON.stringify(injectProjectId(message));
112
+ const parsed = new URL(url);
113
+
114
+ const options = {
115
+ hostname: parsed.hostname,
116
+ port: parsed.port,
117
+ path: parsed.pathname + parsed.search,
118
+ method: "POST",
119
+ headers: {
120
+ "Content-Type": "application/json",
121
+ "Content-Length": Buffer.byteLength(postData),
122
+ },
123
+ };
124
+
125
+ const req = (parsed.protocol === "https:" ? https : http).request(options, (res) => {
126
+ res.resume(); // Drain response
127
+ resolve();
128
+ });
129
+
130
+ req.on("error", (err) => {
131
+ process.stderr.write(`[niro-mcp] POST error: ${err.message}\n`);
132
+ reject(err);
133
+ });
134
+
135
+ req.write(postData);
136
+ req.end();
137
+ });
138
+ }
139
+
140
+ /**
141
+ * Inject project_id into tools/call arguments so the server knows which project to query.
142
+ */
143
+ function injectProjectId(message) {
144
+ if (message.method === "tools/call" && message.params) {
145
+ const args = message.params.arguments || {};
146
+ if (!args.project_id) {
147
+ message.params.arguments = { ...args, project_id: PROJECT_ID };
148
+ }
149
+ }
150
+ return message;
151
+ }
152
+
153
+ /**
154
+ * Main: connect SSE, then read stdin line by line and forward to server.
155
+ */
156
+ async function main() {
157
+ try {
158
+ await connectSse();
159
+ } catch (err) {
160
+ fatal(`Connection failed: ${err.message}`);
161
+ }
162
+
163
+ const rl = readline.createInterface({
164
+ input: process.stdin,
165
+ terminal: false,
166
+ });
167
+
168
+ rl.on("line", async (line) => {
169
+ line = line.trim();
170
+ if (!line) return;
171
+
172
+ try {
173
+ const message = JSON.parse(line);
174
+ await sendMessage(message);
175
+ } catch (err) {
176
+ process.stderr.write(`[niro-mcp] Failed to process message: ${err.message}\n`);
177
+ }
178
+ });
179
+
180
+ rl.on("close", () => {
181
+ process.exit(0);
182
+ });
183
+ }
184
+
185
+ main();
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@niroai/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "Niro MCP Server — code intelligence for AI coding assistants",
5
+ "bin": {
6
+ "mcp-server": "index.js"
7
+ },
8
+ "main": "index.js",
9
+ "keywords": [
10
+ "mcp",
11
+ "model-context-protocol",
12
+ "code-intelligence",
13
+ "claude",
14
+ "cursor",
15
+ "windsurf",
16
+ "niro"
17
+ ],
18
+ "author": "Niro AI <support@niroai.dev>",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/niroai/mcp-server.git"
23
+ },
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
27
+ "files": [
28
+ "index.js",
29
+ "README.md",
30
+ "LICENSE"
31
+ ]
32
+ }