@nooriel/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/package.json +37 -0
- package/server.mjs +155 -0
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nooriel/mcp-bridge",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP bridge for Nooriel — connects coding agents (Codex, Claude Code, Cursor, Windsurf, Kiro) to Nooriel's Build Instruction Pack via MCP protocol.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"nooriel-mcp": "./server.mjs"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"server.mjs"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"nooriel",
|
|
15
|
+
"coding-agent",
|
|
16
|
+
"build-instructions",
|
|
17
|
+
"prototype",
|
|
18
|
+
"windsurf",
|
|
19
|
+
"cursor",
|
|
20
|
+
"claude-code",
|
|
21
|
+
"codex",
|
|
22
|
+
"kiro"
|
|
23
|
+
],
|
|
24
|
+
"author": "Nooriel <hello@nooriel.com>",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/Nooriel/nooriel-2.0-backend",
|
|
29
|
+
"directory": "mcp-bridge"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/server.mjs
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Nooriel MCP Bridge — connects coding agents to Nooriel's Build Instruction Pack.
|
|
5
|
+
*
|
|
6
|
+
* This is a stdio-based MCP server that wraps Nooriel's REST API.
|
|
7
|
+
* Coding agents (Windsurf, Claude Code, Codex, Cursor) connect to this
|
|
8
|
+
* bridge via stdio, and it fetches data from Nooriel's backend.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* NOORIEL_API_BASE=https://... NOORIEL_TOKEN=xxx node server.mjs
|
|
12
|
+
*
|
|
13
|
+
* Or via npx (once published):
|
|
14
|
+
* npx @nooriel/mcp-bridge
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
|
+
|
|
20
|
+
const API_BASE = process.env.NOORIEL_API_BASE || "";
|
|
21
|
+
const TOKEN = process.env.NOORIEL_TOKEN || "";
|
|
22
|
+
|
|
23
|
+
if (!API_BASE || !TOKEN) {
|
|
24
|
+
console.error(
|
|
25
|
+
"Missing env vars. Set NOORIEL_API_BASE and NOORIEL_TOKEN.\n" +
|
|
26
|
+
"Example:\n" +
|
|
27
|
+
' NOORIEL_API_BASE="https://nooriel-backend-293682423253.us-central1.run.app/mcp/v1/projects/YOUR_PROJECT_ID" \\\n' +
|
|
28
|
+
' NOORIEL_TOKEN="your_mcp_token" \\\n' +
|
|
29
|
+
" node server.mjs"
|
|
30
|
+
);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function apiFetch(path) {
|
|
35
|
+
const url = `${API_BASE}${path}`;
|
|
36
|
+
const res = await fetch(url, {
|
|
37
|
+
headers: { "X-MCP-Token": TOKEN },
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const text = await res.text();
|
|
41
|
+
throw new Error(`API ${res.status}: ${text}`);
|
|
42
|
+
}
|
|
43
|
+
return res.json();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Create MCP server
|
|
47
|
+
const server = new McpServer({
|
|
48
|
+
name: "nooriel",
|
|
49
|
+
version: "1.0.0",
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// ── Tools ──────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
server.tool(
|
|
55
|
+
"get_build_pack",
|
|
56
|
+
"Get the Build Instruction Pack — list of all 13 instruction files and metadata. Call this first.",
|
|
57
|
+
{},
|
|
58
|
+
async () => {
|
|
59
|
+
const data = await apiFetch("/build-pack");
|
|
60
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
server.tool(
|
|
65
|
+
"get_build_pack_file",
|
|
66
|
+
"Get a single instruction file by filename (e.g., '00-MASTER-PROMPT.md')",
|
|
67
|
+
{
|
|
68
|
+
filename: { type: "string", description: "Filename from the pack (e.g., '00-MASTER-PROMPT.md')" },
|
|
69
|
+
},
|
|
70
|
+
async ({ filename }) => {
|
|
71
|
+
const data = await apiFetch(`/build-pack/files/${encodeURIComponent(filename)}`);
|
|
72
|
+
return { content: [{ type: "text", text: data.content || JSON.stringify(data) }] };
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
server.tool(
|
|
77
|
+
"get_all_files",
|
|
78
|
+
"Get ALL 13 instruction files in one call. Returns the complete Build Instruction Pack.",
|
|
79
|
+
{},
|
|
80
|
+
async () => {
|
|
81
|
+
const data = await apiFetch("/build-pack/all");
|
|
82
|
+
// Format as readable text with file separators
|
|
83
|
+
let text = `# Build Instruction Pack: ${data.project_name}\n\n`;
|
|
84
|
+
for (const [name, content] of Object.entries(data.files || {})) {
|
|
85
|
+
text += `\n---\n## ${name}\n\n${content}\n`;
|
|
86
|
+
}
|
|
87
|
+
return { content: [{ type: "text", text }] };
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
server.tool(
|
|
92
|
+
"get_project_context",
|
|
93
|
+
"Get a high-level project summary — name, stage, progress.",
|
|
94
|
+
{},
|
|
95
|
+
async () => {
|
|
96
|
+
const data = await apiFetch("/context");
|
|
97
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
server.tool(
|
|
102
|
+
"report_progress",
|
|
103
|
+
"Report build progress to the founder. Call this periodically.",
|
|
104
|
+
{
|
|
105
|
+
current_task: { type: "string", description: "What you're currently working on" },
|
|
106
|
+
files_created: { type: "string", description: "Comma-separated list of files created so far" },
|
|
107
|
+
},
|
|
108
|
+
async ({ current_task, files_created }) => {
|
|
109
|
+
const res = await fetch(`${API_BASE}/build-pack/progress`, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: { "X-MCP-Token": TOKEN, "Content-Type": "application/json" },
|
|
112
|
+
body: JSON.stringify({ current_task, files_created: files_created || "" }),
|
|
113
|
+
});
|
|
114
|
+
const data = await res.json();
|
|
115
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
server.tool(
|
|
120
|
+
"report_complete",
|
|
121
|
+
"Signal that the build is complete. Include the commit SHA if you pushed to GitHub.",
|
|
122
|
+
{
|
|
123
|
+
summary: { type: "string", description: "Brief summary of what was built" },
|
|
124
|
+
commit_sha: { type: "string", description: "Git commit SHA (optional)" },
|
|
125
|
+
},
|
|
126
|
+
async ({ summary, commit_sha }) => {
|
|
127
|
+
const res = await fetch(`${API_BASE}/build-pack/complete`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: { "X-MCP-Token": TOKEN, "Content-Type": "application/json" },
|
|
130
|
+
body: JSON.stringify({ summary: summary || "", commit_sha: commit_sha || "" }),
|
|
131
|
+
});
|
|
132
|
+
const data = await res.json();
|
|
133
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// ── Resources ──────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
server.resource(
|
|
140
|
+
"nooriel://build-pack",
|
|
141
|
+
"nooriel://build-pack",
|
|
142
|
+
async (uri) => {
|
|
143
|
+
const data = await apiFetch("/build-pack/all");
|
|
144
|
+
let text = `# Build Instruction Pack: ${data.project_name}\n\n`;
|
|
145
|
+
for (const [name, content] of Object.entries(data.files || {})) {
|
|
146
|
+
text += `\n---\n## ${name}\n\n${content}\n`;
|
|
147
|
+
}
|
|
148
|
+
return { contents: [{ uri: uri.href, text, mimeType: "text/markdown" }] };
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// ── Start ──────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
const transport = new StdioServerTransport();
|
|
155
|
+
await server.connect(transport);
|