fqrgen-mcp 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 (3) hide show
  1. package/README.md +232 -0
  2. package/index.js +240 -0
  3. package/package.json +34 -0
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # fQRGen MCP Server
2
+
3
+ fQRGen REST API를 [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) 도구로 제공하는 서버입니다.
4
+ AI 에이전트(Claude Code, Claude Desktop 등)에서 QR 코드를 직접 생성할 수 있습니다.
5
+
6
+ ## 전제 조건
7
+
8
+ fQRGen REST API 서버가 실행 중이어야 합니다:
9
+
10
+ | 서버 | 실행 방법 |
11
+ | ----------------- | ------------------------------------------ |
12
+ | macOS 네이티브 앱 | fQRGen.app 실행 (설정에서 REST API 활성화) |
13
+ | Node.js 웹 앱 | `cd lib/qrgen-node && npm start` |
14
+
15
+ 기본 서버 주소: `http://localhost:3014`
16
+
17
+ ---
18
+
19
+ ## 설치
20
+
21
+ ### 방법 1: npx (설치 없이 바로 실행)
22
+
23
+ 별도 설치 없이 MCP 설정에서 `npx`로 직접 실행합니다. (권장)
24
+
25
+ ### 방법 2: 글로벌 설치
26
+
27
+ ```bash
28
+ npm install -g fqrgen-mcp
29
+ ```
30
+
31
+ ### 방법 3: 소스에서 직접 실행
32
+
33
+ ```bash
34
+ git clone https://github.com/nowage/fQRGen.git
35
+ cd fQRGen/_public/mcp
36
+ npm install
37
+ ```
38
+
39
+ ---
40
+
41
+ ## 설정
42
+
43
+ ### Claude Code
44
+
45
+ `~/.claude/settings.json` 또는 프로젝트 `.claude/settings.json`에 추가:
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "fqrgen": {
51
+ "command": "npx",
52
+ "args": ["-y", "fqrgen-mcp"]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ 서버 주소를 변경하려면:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "fqrgen": {
64
+ "command": "npx",
65
+ "args": ["-y", "fqrgen-mcp", "--server=http://192.168.0.10:3014"]
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### Claude Desktop
72
+
73
+ `claude_desktop_config.json`에 추가:
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "fqrgen": {
79
+ "command": "npx",
80
+ "args": ["-y", "fqrgen-mcp"]
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ ### 글로벌 설치 후 사용
87
+
88
+ ```json
89
+ {
90
+ "mcpServers": {
91
+ "fqrgen": {
92
+ "command": "fqrgen-mcp"
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ ### 환경 변수
99
+
100
+ `FQRGEN_SERVER` 환경변수로 서버 주소를 지정할 수 있습니다:
101
+
102
+ ```json
103
+ {
104
+ "mcpServers": {
105
+ "fqrgen": {
106
+ "command": "npx",
107
+ "args": ["-y", "fqrgen-mcp"],
108
+ "env": {
109
+ "FQRGEN_SERVER": "http://192.168.0.10:3014"
110
+ }
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 제공 도구 (Tools)
119
+
120
+ ### 1. `health_check`
121
+
122
+ fQRGen 서버 상태를 확인합니다.
123
+
124
+ **파라미터**: 없음
125
+
126
+ **응답 예시**:
127
+ ```json
128
+ {
129
+ "status": "ok",
130
+ "app": "fQRGen",
131
+ "port": 3014
132
+ }
133
+ ```
134
+
135
+ ---
136
+
137
+ ### 2. `generate_qr`
138
+
139
+ 텍스트 또는 URL로 QR 코드를 생성합니다.
140
+
141
+ **파라미터**:
142
+
143
+ | 이름 | 타입 | 필수 | 기본값 | 설명 |
144
+ | ----------- | ------------------ | ------ | ----------------------- | ------------------------- |
145
+ | `data` | string | 아니오 | `"https://example.com"` | QR 코드에 인코딩할 데이터 |
146
+ | `format` | `"png"` \| `"svg"` | 아니오 | `"png"` | 출력 형식 |
147
+ | `save_path` | string | 아니오 | - | 파일 저장 경로 |
148
+
149
+ **동작**:
150
+ - `save_path` 지정 시: 파일로 저장하고 경로를 반환
151
+ - `format=svg`: SVG XML 문자열을 텍스트로 반환
152
+ - `format=png`: Base64 인코딩된 PNG 이미지를 반환
153
+
154
+ **사용 예시** (Claude에게 요청):
155
+ ```
156
+ "https://finfra.kr" QR 코드를 PNG로 생성해서 ~/Downloads/finfra-qr.png에 저장해줘
157
+ ```
158
+
159
+ ---
160
+
161
+ ### 3. `generate_qr_batch`
162
+
163
+ 여러 개의 QR 코드를 일괄 생성합니다.
164
+
165
+ **파라미터**:
166
+
167
+ | 이름 | 타입 | 필수 | 설명 |
168
+ | ------------------- | ------------------ | ------ | --------------------- |
169
+ | `items` | array | 예 | QR 코드 목록 |
170
+ | `items[].data` | string | 예 | 인코딩할 데이터 |
171
+ | `items[].format` | `"png"` \| `"svg"` | 아니오 | 출력 형식 (기본: png) |
172
+ | `items[].save_path` | string | 예 | 저장 경로 |
173
+
174
+ **사용 예시** (Claude에게 요청):
175
+ ```
176
+ 다음 URL들을 QR 코드로 만들어줘:
177
+ - https://finfra.kr → ~/Downloads/finfra.png
178
+ - https://github.com → ~/Downloads/github.png
179
+ - https://example.com → ~/Downloads/example.png
180
+ ```
181
+
182
+ ---
183
+
184
+ ## 디버깅
185
+
186
+ ### MCP Inspector로 테스트
187
+
188
+ ```bash
189
+ npx @modelcontextprotocol/inspector npx fqrgen-mcp
190
+ ```
191
+
192
+ 브라우저에서 Inspector UI가 열리며, 각 도구를 직접 테스트할 수 있습니다.
193
+
194
+ ### 서버 연결 확인
195
+
196
+ ```bash
197
+ # fQRGen REST API 서버가 실행 중인지 확인
198
+ curl http://localhost:3014/
199
+ ```
200
+
201
+ ---
202
+
203
+ ## npm 배포
204
+
205
+ ```bash
206
+ cd _public/mcp
207
+ npm publish
208
+ ```
209
+
210
+ ---
211
+
212
+ ## 아키텍처
213
+
214
+ ```
215
+ Claude Code / Claude Desktop
216
+
217
+ │ MCP (stdio)
218
+
219
+ fqrgen-mcp (이 서버)
220
+
221
+ │ HTTP (REST API)
222
+
223
+ fQRGen Server (localhost:3014)
224
+ ├── macOS 네이티브 앱 (Swift)
225
+ └── Node.js 웹 앱 (Express)
226
+ ```
227
+
228
+ ---
229
+
230
+ ## 라이선스
231
+
232
+ MIT
package/index.js ADDED
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * fQRGen MCP Server
5
+ *
6
+ * Usage:
7
+ * node index.js [--server=<url>]
8
+ *
9
+ * Arguments:
10
+ * --server=<url> : (옵션) fQRGen REST API 서버 주소 (기본값: http://localhost:3014)
11
+ *
12
+ * Environment:
13
+ * FQRGEN_SERVER : fQRGen REST API 서버 주소 (--server 옵션보다 우선순위 낮음)
14
+ */
15
+
16
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import { z } from "zod";
19
+ import { writeFile } from "node:fs/promises";
20
+ import { resolve } from "node:path";
21
+
22
+ // 서버 주소 결정: CLI 인자 > 환경변수 > 기본값
23
+ function getServerUrl() {
24
+ const arg = process.argv.find((a) => a.startsWith("--server="));
25
+ if (arg) return arg.split("=").slice(1).join("=");
26
+ return process.env.FQRGEN_SERVER || "http://localhost:3014";
27
+ }
28
+
29
+ const SERVER_URL = getServerUrl();
30
+
31
+ const server = new McpServer({
32
+ name: "fqrgen-mcp",
33
+ version: "1.0.0",
34
+ });
35
+
36
+ // Tool: health_check
37
+ server.tool(
38
+ "health_check",
39
+ "fQRGen 서버 상태를 확인합니다",
40
+ {},
41
+ async () => {
42
+ try {
43
+ const res = await fetch(SERVER_URL);
44
+ const contentType = res.headers.get("content-type") || "";
45
+
46
+ if (contentType.includes("application/json")) {
47
+ const json = await res.json();
48
+ return {
49
+ content: [
50
+ {
51
+ type: "text",
52
+ text: JSON.stringify(json, null, 2),
53
+ },
54
+ ],
55
+ };
56
+ }
57
+
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: `서버 응답: ${res.status} ${res.statusText} (HTML UI - Node.js 서버)`,
63
+ },
64
+ ],
65
+ };
66
+ } catch (err) {
67
+ return {
68
+ isError: true,
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: `서버 연결 실패: ${err.message}\n서버 주소: ${SERVER_URL}`,
73
+ },
74
+ ],
75
+ };
76
+ }
77
+ }
78
+ );
79
+
80
+ // Tool: generate_qr
81
+ server.tool(
82
+ "generate_qr",
83
+ "텍스트 또는 URL로 QR 코드를 생성합니다. PNG 바이너리 또는 SVG 문자열을 반환합니다.",
84
+ {
85
+ data: z
86
+ .string()
87
+ .default("https://example.com")
88
+ .describe("QR 코드에 인코딩할 텍스트 또는 URL"),
89
+ format: z
90
+ .enum(["png", "svg"])
91
+ .default("png")
92
+ .describe("출력 형식: png 또는 svg"),
93
+ save_path: z
94
+ .string()
95
+ .optional()
96
+ .describe("(옵션) 생성된 QR 이미지를 저장할 파일 경로"),
97
+ },
98
+ async ({ data, format, save_path }) => {
99
+ try {
100
+ const res = await fetch(`${SERVER_URL}/api/generate`, {
101
+ method: "POST",
102
+ headers: { "Content-Type": "application/json" },
103
+ body: JSON.stringify({ data, format }),
104
+ });
105
+
106
+ if (!res.ok) {
107
+ const errBody = await res.text();
108
+ return {
109
+ isError: true,
110
+ content: [
111
+ {
112
+ type: "text",
113
+ text: `QR 생성 실패 (${res.status}): ${errBody}`,
114
+ },
115
+ ],
116
+ };
117
+ }
118
+
119
+ const buffer = Buffer.from(await res.arrayBuffer());
120
+
121
+ // 파일 저장 요청이 있으면 저장
122
+ if (save_path) {
123
+ const absPath = resolve(save_path);
124
+ await writeFile(absPath, buffer);
125
+ return {
126
+ content: [
127
+ {
128
+ type: "text",
129
+ text: `QR 코드 저장 완료: ${absPath} (${format.toUpperCase()}, ${buffer.length} bytes)\n인코딩 데이터: ${data}`,
130
+ },
131
+ ],
132
+ };
133
+ }
134
+
135
+ // SVG는 텍스트로 반환
136
+ if (format === "svg") {
137
+ return {
138
+ content: [
139
+ {
140
+ type: "text",
141
+ text: buffer.toString("utf-8"),
142
+ },
143
+ ],
144
+ };
145
+ }
146
+
147
+ // PNG는 base64 이미지로 반환
148
+ return {
149
+ content: [
150
+ {
151
+ type: "image",
152
+ data: buffer.toString("base64"),
153
+ mimeType: "image/png",
154
+ },
155
+ {
156
+ type: "text",
157
+ text: `QR 코드 생성 완료 (PNG, ${buffer.length} bytes)\n인코딩 데이터: ${data}`,
158
+ },
159
+ ],
160
+ };
161
+ } catch (err) {
162
+ return {
163
+ isError: true,
164
+ content: [
165
+ {
166
+ type: "text",
167
+ text: `QR 생성 오류: ${err.message}\n서버 주소: ${SERVER_URL}`,
168
+ },
169
+ ],
170
+ };
171
+ }
172
+ }
173
+ );
174
+
175
+ // Tool: generate_qr_batch
176
+ server.tool(
177
+ "generate_qr_batch",
178
+ "여러 개의 QR 코드를 일괄 생성합니다",
179
+ {
180
+ items: z
181
+ .array(
182
+ z.object({
183
+ data: z.string().describe("QR 코드에 인코딩할 텍스트 또는 URL"),
184
+ format: z
185
+ .enum(["png", "svg"])
186
+ .default("png")
187
+ .describe("출력 형식"),
188
+ save_path: z.string().describe("저장할 파일 경로"),
189
+ })
190
+ )
191
+ .describe("생성할 QR 코드 목록"),
192
+ },
193
+ async ({ items }) => {
194
+ const results = [];
195
+
196
+ for (const item of items) {
197
+ try {
198
+ const res = await fetch(`${SERVER_URL}/api/generate`, {
199
+ method: "POST",
200
+ headers: { "Content-Type": "application/json" },
201
+ body: JSON.stringify({ data: item.data, format: item.format }),
202
+ });
203
+
204
+ if (!res.ok) {
205
+ results.push(`FAIL: ${item.data} → ${res.status} 에러`);
206
+ continue;
207
+ }
208
+
209
+ const buffer = Buffer.from(await res.arrayBuffer());
210
+ const absPath = resolve(item.save_path);
211
+ await writeFile(absPath, buffer);
212
+ results.push(
213
+ `OK: ${item.data} → ${absPath} (${buffer.length} bytes)`
214
+ );
215
+ } catch (err) {
216
+ results.push(`FAIL: ${item.data} → ${err.message}`);
217
+ }
218
+ }
219
+
220
+ return {
221
+ content: [
222
+ {
223
+ type: "text",
224
+ text: `일괄 생성 결과 (${results.length}건):\n${results.join("\n")}`,
225
+ },
226
+ ],
227
+ };
228
+ }
229
+ );
230
+
231
+ // 서버 시작
232
+ async function main() {
233
+ const transport = new StdioServerTransport();
234
+ await server.connect(transport);
235
+ }
236
+
237
+ main().catch((err) => {
238
+ console.error("MCP 서버 시작 실패:", err);
239
+ process.exit(1);
240
+ });
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "fqrgen-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for fQRGen QR code generation via REST API",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "fqrgen-mcp": "./index.js"
9
+ },
10
+ "files": [
11
+ "index.js"
12
+ ],
13
+ "scripts": {
14
+ "start": "node index.js"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "qrcode",
19
+ "fqrgen",
20
+ "model-context-protocol"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/nowage/fQRGen.git",
25
+ "directory": "_public/mcp"
26
+ },
27
+ "engines": {
28
+ "node": ">=18.0.0"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.12.1"
32
+ },
33
+ "license": "MIT"
34
+ }