@hoagsmedia/frugr-mcp 0.2.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 +22 -0
- package/index.mjs +84 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @hoagsmedia/frugr-mcp
|
|
2
|
+
|
|
3
|
+
Preferred npm name for the frugr **read-only** MCP stdio bridge.
|
|
4
|
+
|
|
5
|
+
This package is identical to [`@hoagsmedia/frgur-mcp-server`](https://www.npmjs.com/package/@hoagsmedia/frgur-mcp-server) v0.2.0 — same `index.mjs`, same env vars (`FRGUR_API_TOKEN`, `FRGUR_API_URL`). The legacy `frgur` spelling remains for backward compatibility.
|
|
6
|
+
|
|
7
|
+
Full setup, tool list, and security notes: [mcp-server README on GitHub](https://github.com/hoagsmedia/frugr/blob/main/mcp-server/README.md) or the [`frgur-mcp-server` npm page](https://www.npmjs.com/package/@hoagsmedia/frgur-mcp-server).
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"frugr": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "@hoagsmedia/frugr-mcp@0.2.0"],
|
|
15
|
+
"env": {
|
|
16
|
+
"FRGUR_API_URL": "https://app.frgur.com",
|
|
17
|
+
"FRGUR_API_TOKEN": "frgur_pat_your_token_here"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
package/index.mjs
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @hoagsmedia/frgur-mcp-server — a thin, READ-ONLY MCP bridge to your frugr books.
|
|
3
|
+
//
|
|
4
|
+
// It exposes frugr's books tools over stdio (for Cursor / Claude Desktop /
|
|
5
|
+
// Claude Code / ChatGPT) and forwards every call to the frugr API using your
|
|
6
|
+
// Personal Access Token. The bridge holds no credentials of its own, runs your
|
|
7
|
+
// own AI client's model (not frugr's), and can only read — it never writes.
|
|
8
|
+
//
|
|
9
|
+
// Config (env):
|
|
10
|
+
// FRGUR_API_TOKEN required — a token from frugr → Settings → External AI apps
|
|
11
|
+
// FRGUR_API_URL optional — your frugr origin (default https://app.frgur.com)
|
|
12
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
13
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { dirname, join } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
|
|
19
|
+
const PKG = JSON.parse(
|
|
20
|
+
readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'package.json'), 'utf8')
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const API_URL = (process.env.FRGUR_API_URL ?? 'https://app.frgur.com').replace(/\/+$/, '');
|
|
24
|
+
const API_TOKEN = process.env.FRGUR_API_TOKEN ?? '';
|
|
25
|
+
const ENDPOINT = `${API_URL}/api/mcp`;
|
|
26
|
+
|
|
27
|
+
// Diagnostics MUST go to stderr — stdout is the MCP protocol channel.
|
|
28
|
+
function logErr(msg) {
|
|
29
|
+
process.stderr.write(`[frgur-mcp] ${msg}\n`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!API_TOKEN) {
|
|
33
|
+
logErr('FRGUR_API_TOKEN is required. Create one in frugr → Settings → External AI apps (MCP).');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** POST one bridge request to the frugr endpoint, authenticated by the PAT. */
|
|
38
|
+
async function call(method, params) {
|
|
39
|
+
let res;
|
|
40
|
+
try {
|
|
41
|
+
res = await fetch(ENDPOINT, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${API_TOKEN}` },
|
|
44
|
+
body: JSON.stringify({ method, params })
|
|
45
|
+
});
|
|
46
|
+
} catch (e) {
|
|
47
|
+
throw new Error(`Could not reach frugr at ${ENDPOINT}: ${e?.message ?? e}`, { cause: e });
|
|
48
|
+
}
|
|
49
|
+
const text = await res.text();
|
|
50
|
+
let data;
|
|
51
|
+
try {
|
|
52
|
+
data = text ? JSON.parse(text) : {};
|
|
53
|
+
} catch {
|
|
54
|
+
data = { error: text };
|
|
55
|
+
}
|
|
56
|
+
if (!res.ok) throw new Error(data?.error ?? `frugr API error ${res.status}`);
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const server = new Server(
|
|
61
|
+
{ name: 'frgur-books', version: PKG.version },
|
|
62
|
+
{ capabilities: { tools: {} } }
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Tool list comes straight from frugr, so adding a tool server-side surfaces it
|
|
66
|
+
// to every client with no package update.
|
|
67
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
68
|
+
const { tools } = await call('tools/list');
|
|
69
|
+
return { tools: tools ?? [] };
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
73
|
+
const { name, arguments: args } = request.params;
|
|
74
|
+
const result = await call('tools/call', { name, arguments: args ?? {} });
|
|
75
|
+
// frugr already returns an MCP CallTool result ({ content, isError }); pass it
|
|
76
|
+
// through, falling back to stringifying anything unexpected.
|
|
77
|
+
return {
|
|
78
|
+
content: result.content ?? [{ type: 'text', text: JSON.stringify(result) }],
|
|
79
|
+
isError: Boolean(result.isError)
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await server.connect(new StdioServerTransport());
|
|
84
|
+
logErr(`connected to ${API_URL} — read-only books tools available.`);
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hoagsmedia/frugr-mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Read-only MCP bridge to your frugr books (12 tools). Preferred npm name — alias of @hoagsmedia/frgur-mcp-server.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"frugr-mcp": "index.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.mjs",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/hoagsmedia/frugr.git",
|
|
26
|
+
"directory": "mcp-server/frugr-alias"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/hoagsmedia/frugr/tree/main/mcp-server#mcp-stdio-bridge"
|
|
29
|
+
}
|