@pwarnock/kjbc-mcp 0.1.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/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @pwarnock/kjbc-mcp
2
+
3
+ Strong's Concordance MCP server for AI assistants. Provides grounded Greek/Hebrew word lookups from the King James Bible Concordance.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npx @pwarnock/kjbc-mcp
9
+ ```
10
+
11
+ Or add to your MCP configuration:
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "kjbc": {
17
+ "command": "npx",
18
+ "args": ["-y", "@pwarnock/kjbc-mcp"]
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ ## Tools
25
+
26
+ - **word** - Find Strong's entries for an English word
27
+ - **entry** - Get details for a Strong's number (definition, pronunciation)
28
+ - **langs** - List supported languages (Greek, Hebrew)
29
+
30
+ ## Example
31
+
32
+ Ask your AI assistant:
33
+ > "What's the Greek word for 'love' in the New Testament?"
34
+
35
+ The assistant can look up Strong's G25 (agapao) and G26 (agape) with full definitions.
36
+
37
+ ## License
38
+
39
+ GPL-3.0
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require("child_process");
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+
7
+ const binaryName = process.platform === "win32" ? "kjbc-mcp.exe" : "kjbc-mcp";
8
+ const binaryPath = path.join(__dirname, binaryName);
9
+
10
+ if (!fs.existsSync(binaryPath)) {
11
+ console.error(
12
+ `[kjbc-mcp] Binary not found at ${binaryPath}\n` +
13
+ `Run: npm rebuild @pwarnock/kjbc-mcp`
14
+ );
15
+ process.exit(1);
16
+ }
17
+
18
+ const child = spawn(binaryPath, process.argv.slice(2), {
19
+ stdio: "inherit",
20
+ });
21
+
22
+ child.on("error", (err) => {
23
+ console.error(`[kjbc-mcp] Failed to start: ${err.message}`);
24
+ process.exit(1);
25
+ });
26
+
27
+ child.on("exit", (code) => {
28
+ process.exit(code ?? 0);
29
+ });
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@pwarnock/kjbc-mcp",
3
+ "version": "0.1.0",
4
+ "description": "Strong's Concordance MCP server - Greek/Hebrew word lookups for AI assistants",
5
+ "bin": {
6
+ "kjbc-mcp": "./bin/kjbc-mcp.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/postinstall.js"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/pwarnock/kjbc-mcp"
14
+ },
15
+ "author": "pwarnock",
16
+ "license": "GPL-3.0",
17
+ "keywords": [
18
+ "mcp",
19
+ "model-context-protocol",
20
+ "bible",
21
+ "strongs",
22
+ "concordance",
23
+ "greek",
24
+ "hebrew",
25
+ "ai"
26
+ ],
27
+ "engines": {
28
+ "node": ">=16.0.0"
29
+ },
30
+ "files": [
31
+ "bin/",
32
+ "scripts/",
33
+ "README.md"
34
+ ]
35
+ }
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Postinstall script for @pwarnock/kjbc-mcp
5
+ * Downloads the correct platform-specific Go binary from GitHub releases
6
+ */
7
+
8
+ const fs = require("fs");
9
+ const path = require("path");
10
+ const https = require("https");
11
+ const { execFileSync } = require("child_process");
12
+
13
+ const pkg = require("../package.json");
14
+ const REPO = "pwarnock/kjbc-mcp";
15
+ const BINARY_NAME = "kjbc-mcp";
16
+
17
+ function log(msg) {
18
+ console.log(`[${pkg.name}] ${msg}`);
19
+ }
20
+
21
+ function error(msg) {
22
+ console.error(`[${pkg.name}] ${msg}`);
23
+ }
24
+
25
+ /**
26
+ * Detect platform and architecture
27
+ */
28
+ function getPlatformInfo() {
29
+ const platform = process.platform;
30
+ const arch = process.arch;
31
+
32
+ // Map Node.js platform/arch to Go naming convention
33
+ const platformMap = {
34
+ darwin: "darwin",
35
+ linux: "linux",
36
+ win32: "windows",
37
+ };
38
+
39
+ const archMap = {
40
+ x64: "amd64",
41
+ arm64: "arm64",
42
+ };
43
+
44
+ const goPlatform = platformMap[platform];
45
+ const goArch = archMap[arch];
46
+
47
+ if (!goPlatform || !goArch) {
48
+ return null;
49
+ }
50
+
51
+ return {
52
+ platform: goPlatform,
53
+ arch: goArch,
54
+ extension: platform === "win32" ? ".exe" : "",
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Download file with redirect support
60
+ */
61
+ function download(url) {
62
+ return new Promise((resolve, reject) => {
63
+ const request = https.get(url, (response) => {
64
+ // Handle redirects (GitHub releases use them)
65
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
66
+ return download(response.headers.location).then(resolve).catch(reject);
67
+ }
68
+
69
+ if (response.statusCode !== 200) {
70
+ return reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
71
+ }
72
+
73
+ const chunks = [];
74
+ response.on("data", (chunk) => chunks.push(chunk));
75
+ response.on("end", () => resolve(Buffer.concat(chunks)));
76
+ response.on("error", reject);
77
+ });
78
+
79
+ request.on("error", reject);
80
+ request.setTimeout(60000, () => {
81
+ request.destroy();
82
+ reject(new Error("Download timeout"));
83
+ });
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Extract tar.gz using system tar (available on macOS, Linux, and modern Windows)
89
+ * Uses execFileSync to avoid shell injection
90
+ */
91
+ function extractTarGz(tarBuffer, destDir) {
92
+ const tarPath = path.join(destDir, "temp.tar.gz");
93
+ fs.writeFileSync(tarPath, tarBuffer);
94
+
95
+ try {
96
+ // Use execFileSync instead of execSync to avoid shell injection
97
+ execFileSync("tar", ["-xzf", tarPath, "-C", destDir], { stdio: "pipe" });
98
+ } finally {
99
+ fs.unlinkSync(tarPath);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Main installation
105
+ */
106
+ async function main() {
107
+ const platformInfo = getPlatformInfo();
108
+
109
+ if (!platformInfo) {
110
+ error(`Unsupported platform: ${process.platform}/${process.arch}`);
111
+ error("Please download the binary manually from:");
112
+ error(`https://github.com/${REPO}/releases`);
113
+ process.exit(0); // Don't fail the install
114
+ }
115
+
116
+ const { platform, arch, extension } = platformInfo;
117
+ const version = pkg.version;
118
+ const archiveName = `${BINARY_NAME}_${platform}_${arch}.tar.gz`;
119
+ const url = `https://github.com/${REPO}/releases/download/v${version}/${archiveName}`;
120
+
121
+ log(`Downloading ${BINARY_NAME} v${version} for ${platform}/${arch}...`);
122
+
123
+ try {
124
+ const tarBuffer = await download(url);
125
+ log("Extracting...");
126
+
127
+ const binDir = path.join(__dirname, "..", "bin");
128
+ extractTarGz(tarBuffer, binDir);
129
+
130
+ // Ensure binary is executable
131
+ const binaryPath = path.join(binDir, BINARY_NAME + extension);
132
+ if (process.platform !== "win32") {
133
+ fs.chmodSync(binaryPath, 0o755);
134
+ }
135
+
136
+ log("Installation complete!");
137
+ } catch (err) {
138
+ error(`Download failed: ${err.message}`);
139
+ error("");
140
+ error("You can install the binary manually:");
141
+ error(`1. Download from: https://github.com/${REPO}/releases`);
142
+ error(`2. Extract to: ${path.join(__dirname, "..", "bin")}`);
143
+ process.exit(0); // Don't fail the install - allows manual setup
144
+ }
145
+ }
146
+
147
+ main();