@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 +39 -0
- package/bin/kjbc-mcp.js +29 -0
- package/package.json +35 -0
- package/scripts/postinstall.js +147 -0
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
|
package/bin/kjbc-mcp.js
ADDED
|
@@ -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();
|