@nhnpayco-dev/mcp-devcenter 1.0.3 → 1.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 +10 -10
- package/dist/data/api-specs.json +3 -17
- package/dist/data/guides/offline-authapi.md +1 -1
- package/dist/data/guides/online-extra.md +7 -17
- package/dist/data/guides/online-extra.meta.json +1 -1
- package/dist/data/guides/online-extradata.md +1 -1
- package/dist/data/index.json +2 -2
- package/dist/excel.js +51 -15
- package/dist/index.js +7 -1
- package/dist/tools.js +42 -19
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -94,10 +94,10 @@ AI 개발 도구에 이렇게 물어보면 됩니다.
|
|
|
94
94
|
|
|
95
95
|
| 도구 이름 | 설명 |
|
|
96
96
|
|---|---|
|
|
97
|
-
| `list_validatable_apis()` | 자동 검증 가능한 API 슬러그
|
|
97
|
+
| `list_validatable_apis()` | 자동 검증 가능한 API 슬러그 34개 목록 (URL·메서드·파라미터 수 포함) |
|
|
98
98
|
| `get_checklist(service)` | 서비스별 사전 검수 체크리스트(자동 + 수동 항목). service: `online`/`offline`/`order`/`membership` |
|
|
99
|
-
| `validate_payload(api, payload)` | API 요청 페이로드 JSON을 검증 — (1) 필수 누락 / 명세 외 파라미터 / 타입 불일치 + (2) 자동 체크리스트(
|
|
100
|
-
| `export_validation_excel(path?, clearAfter?)` | 누적된 검수 결과를 xlsx로 추출. **3개 시트**: 검수요약 / 항목별 상세 /
|
|
99
|
+
| `validate_payload(api, payload)` | API 요청 페이로드 JSON을 검증 — (1) 필수 누락 / 명세 외 파라미터 / 타입 불일치 + (2) 자동 체크리스트(개인정보(멤버십 제외)·URL 인코딩·공백·금액 합산·enum·날짜 형식·returnUrl) + (3) 수동 확인 항목 |
|
|
100
|
+
| `export_validation_excel(path?, clearAfter?)` | 누적된 검수 결과를 xlsx로 추출. **3개 시트**: 검수요약 / 항목별 상세 / 공통검수체크리스트. 다운로드 폴더에만 저장하며(`path`는 파일 이름으로만 사용), 같은 이름이 있으면 덮어쓰지 않고 번호를 붙임 |
|
|
101
101
|
| `clear_validation_buffer()` | 누적된 검수 결과를 모두 초기화 (새 세션 시작 시) |
|
|
102
102
|
|
|
103
103
|
### 검증 도구 사용 예시 (외부 제휴사 시점)
|
|
@@ -158,13 +158,13 @@ AI 개발 도구에 이렇게 물어보면 됩니다.
|
|
|
158
158
|
**calculate** — 결제/정산 대사
|
|
159
159
|
`calculate`
|
|
160
160
|
|
|
161
|
-
🆕 표시는 PAYCO
|
|
161
|
+
🆕 표시는 PAYCO 개발자센터에 게시되지 않은 가이드입니다.
|
|
162
162
|
|
|
163
|
-
### 자동 검증 가능한 API 슬러그 (
|
|
163
|
+
### 자동 검증 가능한 API 슬러그 (34개)
|
|
164
164
|
|
|
165
165
|
**온라인 — reserve / 승인 / 취소**
|
|
166
166
|
`online-easypay-01`~`04` · `online-autopay-01`~`04`/`06` ·
|
|
167
|
-
`online-etc-01`/`03`/`04` · `online-extra-
|
|
167
|
+
`online-etc-01`/`03`/`04` · `online-extra-03`
|
|
168
168
|
(자동결제 ⑤ 결제 취소는 일반 결제 취소 API와 같아 `online-easypay-04`로 검증)
|
|
169
169
|
|
|
170
170
|
**온라인 — reserve 변형 (합성)**
|
|
@@ -192,12 +192,12 @@ VMEM (DLL) `membership-vmem-execasyncapproval` · `-execcomplete` · `-execcance
|
|
|
192
192
|
|
|
193
193
|
본 패키지에 포함된 가이드 정보:
|
|
194
194
|
- [PAYCO 개발자센터](https://devcenter.payco.com)의 **연동하기 > 온라인/오프라인/오더/멤버십** 전 섹션 + **결제/정산 대사**
|
|
195
|
-
-
|
|
195
|
+
- 개발자센터 미게시 가이드 2종: 오프라인 POS **인증승인형 연동 가이드**, **부가정보(extraData) 명세**
|
|
196
196
|
|
|
197
|
-
- 가이드 본문 카테고리: **28개** (devcenter 크롤 26개 +
|
|
197
|
+
- 가이드 본문 카테고리: **28개** (devcenter 크롤 26개 + 개발자센터 미게시 문서 2개)
|
|
198
198
|
- 에러코드/코드값 표 항목: **500+ 개** (4개 root 의 API 응답코드, 결제수단, 카드사, 은행, VAN사, 결제수단 코드 등 통합)
|
|
199
|
-
- 자동 검증 가능한 API 명세: **
|
|
200
|
-
- REST API
|
|
199
|
+
- 자동 검증 가능한 API 명세: **34개**
|
|
200
|
+
- REST API 24개 (easypay/autopay/etc/extra/offline-api/authapi 등)
|
|
201
201
|
- DLL 함수 7개 (offline-vcat, order-vorder, membership-vmem)
|
|
202
202
|
- 합성 변형 슬러그 3개 (`online-easypay-nonmember`/`-checkout`/`-ordersheet`)
|
|
203
203
|
|
package/dist/data/api-specs.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "PAYCO 개발자센터 가이드 markdown 본문에서 자동 추출 + 변형 합성",
|
|
3
|
-
"api_count":
|
|
3
|
+
"api_count": 34,
|
|
4
4
|
"apis": [
|
|
5
5
|
{
|
|
6
6
|
"slug": "online-easypay-01",
|
|
@@ -1857,26 +1857,12 @@
|
|
|
1857
1857
|
"response_total": 3
|
|
1858
1858
|
}
|
|
1859
1859
|
},
|
|
1860
|
-
{
|
|
1861
|
-
"slug": "online-extra-02",
|
|
1862
|
-
"guide": "online-extra",
|
|
1863
|
-
"title": "iOS 앱 스킴(App Url Scheme) 추가하기",
|
|
1864
|
-
"url": "/outseller/payment/approval/getDetailForVerify",
|
|
1865
|
-
"method": "POST",
|
|
1866
|
-
"request_params": [],
|
|
1867
|
-
"response_params": [],
|
|
1868
|
-
"param_counts": {
|
|
1869
|
-
"request_total": 0,
|
|
1870
|
-
"request_required": 0,
|
|
1871
|
-
"response_total": 0
|
|
1872
|
-
}
|
|
1873
|
-
},
|
|
1874
1860
|
{
|
|
1875
1861
|
"slug": "online-extra-03",
|
|
1876
1862
|
"guide": "online-extra",
|
|
1877
1863
|
"title": "결제상세조회 API - REQUEST",
|
|
1878
|
-
"url":
|
|
1879
|
-
"method":
|
|
1864
|
+
"url": "/outseller/payment/approval/getDetailForVerify",
|
|
1865
|
+
"method": "POST",
|
|
1880
1866
|
"request_params": [
|
|
1881
1867
|
{
|
|
1882
1868
|
"name": "sellerKey",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PAYCO 오프라인 POS 인증승인형 연동 가이드
|
|
2
2
|
|
|
3
|
-
> **원본:** PAYCO_오프라인POS_인증승인형연동가이드_v1.0.1.0.docx (
|
|
3
|
+
> **원본:** PAYCO_오프라인POS_인증승인형연동가이드_v1.0.1.0.docx (개발자센터 미게시 문서)
|
|
4
4
|
> **카테고리:** `offline-authapi`
|
|
5
5
|
> **연동 방식:** 가맹점 단말이 결제 인증·승인을 직접 수행하는 인증승인형
|
|
6
6
|
> **API 5종:** POS 인증 / 결제 인증 / 결제 승인 / 결제취소 / 망취소
|
|
@@ -165,26 +165,16 @@ PAYCO App 결제 연동 시 유의 해야 될 내용을 확인 해보세요.
|
|
|
165
165
|
|
|
166
166
|
### 영수증
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
고객 영수증을 보여줄 수 있어요.
|
|
169
|
+
영수증 조회를 위해서는 PAYCO 로그인이 필요하며, 이용자 본인인 경우에만 조회할 수 있습니다.
|
|
170
170
|
|
|
171
171
|
앱 스킴 리스트
|
|
172
172
|
|
|
173
173
|
| | |
|
|
174
174
|
| --- | --- |
|
|
175
|
-
|
|
|
176
|
-
|
|
|
175
|
+
| URL | /outseller/receipt/{orderNo} * orderNo: PAYCO 주문번호 |
|
|
176
|
+
| Method | GET |
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
-
|
|
180
|
-
|
|
181
|
-
▶ 신용카드 매출전표: URL?receiptKind=card
|
|
182
|
-
▶ 온라인 영수증: URL?receiptKind=online
|
|
183
|
-
▶ 가맹점용 Sample URL: https://bill.payco.com/seller/receipt/DEMO_REAL/mallseq1639976172184/202112202536599429
|
|
184
|
-
▶ 고객용 Sample URL: https://bill.payco.com/outseller/receipt/202112202536599429
|
|
185
|
-
|
|
186
|
-
- ##### 가맹점용 영수증
|
|
187
|
-
|
|
188
|
-

|
|
189
|
-
|
|
190
|
-

|
|
178
|
+
영수증 형식을 지정하려는 경우 "receiptKind" 파라미터를 추가하여 호출합니다.
|
|
179
|
+
- 신용카드 매출전표: URL?receiptKind=card
|
|
180
|
+
- 온라인 영수증: URL?receiptKind=online
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PAYCO 부가정보(extraData) 명세
|
|
2
2
|
|
|
3
|
-
> **원본:** PAYCO_부가정보(extraData)_v1.1.14.docx (
|
|
3
|
+
> **원본:** PAYCO_부가정보(extraData)_v1.1.14.docx (개발자센터 미게시 문서)
|
|
4
4
|
> **카테고리:** `online-extradata`
|
|
5
5
|
> **용도:** 온라인결제 주문예약 API의 extraData 파라미터(JSON String) 내부 구조 정의
|
|
6
6
|
> **사용 위치:** online-easypay-01 (reserve), online-autopay-01, online-easypay-nonmember/checkout/ordersheet 등 reserve 계열 API
|
package/dist/data/index.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": "1.0",
|
|
3
3
|
"source_site": "https://devcenter.payco.com",
|
|
4
4
|
"scope": "PAYCO 가이드 전체 (온라인결제·자동결제·오프라인결제·오더클라우드·멤버십클라우드·결제정산대사)",
|
|
5
|
-
"generated_at": "2026-10-
|
|
5
|
+
"generated_at": "2026-10-14T04:35:38+00:00",
|
|
6
6
|
"category_count": 28,
|
|
7
7
|
"categories": [
|
|
8
8
|
{
|
|
@@ -589,7 +589,7 @@
|
|
|
589
589
|
],
|
|
590
590
|
"table_count": 5,
|
|
591
591
|
"code_block_count": 3,
|
|
592
|
-
"text_length":
|
|
592
|
+
"text_length": 4151
|
|
593
593
|
},
|
|
594
594
|
{
|
|
595
595
|
"slug": "online-extradata",
|
package/dist/excel.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// 검수 결과 → xlsx 변환.
|
|
2
2
|
// 3 시트: 검수요약 / 항목별 상세 / 공통검수체크리스트
|
|
3
3
|
// 양식 참조: data/samples/payco_nonmember_checklist.xlsx (Arial 10pt, 진남색 헤더)
|
|
4
|
-
import { mkdir } from "node:fs/promises";
|
|
4
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
|
-
import {
|
|
6
|
+
import { join } from "node:path";
|
|
7
7
|
import ExcelJS from "exceljs";
|
|
8
8
|
import { CHECKLISTS, SERVICE_LABELS } from "./tools.js";
|
|
9
9
|
// ── 디자인 토큰 ──────────────────────────────────────────────
|
|
@@ -30,21 +30,49 @@ const STATUS_LABEL = {
|
|
|
30
30
|
manual: "⬜ 수동확인",
|
|
31
31
|
};
|
|
32
32
|
// ── 경로/파일명 ──────────────────────────────────────────────
|
|
33
|
-
|
|
33
|
+
// 저장 위치는 항상 다운로드 폴더로 고정한다. 경로는 AI 가 정해 넘기므로
|
|
34
|
+
// 다른 폴더 저장·폴더 생성·기존 파일 덮어쓰기를 허용하지 않는다.
|
|
35
|
+
export function downloadsDir() {
|
|
36
|
+
return join(homedir(), "Downloads");
|
|
37
|
+
}
|
|
38
|
+
function defaultFileName() {
|
|
34
39
|
const now = new Date();
|
|
35
40
|
const pad = (n) => String(n).padStart(2, "0");
|
|
36
41
|
const stamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}` +
|
|
37
42
|
`-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
38
|
-
return
|
|
43
|
+
return `payco-validation-${stamp}.xlsx`;
|
|
44
|
+
}
|
|
45
|
+
/** 요청 경로에서 파일명만 남긴다. 폴더 부분이 있었으면 relocated=true. */
|
|
46
|
+
function toFileName(userPath) {
|
|
47
|
+
const raw = userPath?.trim() ?? "";
|
|
48
|
+
if (!raw)
|
|
49
|
+
return { name: defaultFileName(), relocated: false };
|
|
50
|
+
const parts = raw.split(/[\\/]/);
|
|
51
|
+
const relocated = parts.length > 1;
|
|
52
|
+
let name = parts[parts.length - 1]
|
|
53
|
+
.replace(/[<>:"|?*\u0000-\u001f]/g, "_")
|
|
54
|
+
.replace(/[. ]+$/, "");
|
|
55
|
+
if (!name || name === "..")
|
|
56
|
+
name = defaultFileName();
|
|
57
|
+
if (!name.toLowerCase().endsWith(".xlsx"))
|
|
58
|
+
name = `${name}.xlsx`;
|
|
59
|
+
return { name, relocated };
|
|
39
60
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
/** 같은 이름이 있으면 ' (2)', ' (3)' … 을 붙여 새 파일로 쓴다(덮어쓰기 금지). */
|
|
62
|
+
async function writeNoOverwrite(dir, name, data) {
|
|
63
|
+
const base = name.slice(0, -".xlsx".length);
|
|
64
|
+
for (let i = 1; i < 1000; i++) {
|
|
65
|
+
const p = join(dir, i === 1 ? name : `${base} (${i}).xlsx`);
|
|
66
|
+
try {
|
|
67
|
+
await writeFile(p, data, { flag: "wx" });
|
|
68
|
+
return p;
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
if (e.code !== "EEXIST")
|
|
72
|
+
throw e;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`같은 이름의 파일이 너무 많습니다: ${name}`);
|
|
48
76
|
}
|
|
49
77
|
// ── 공통 헬퍼 ────────────────────────────────────────────────
|
|
50
78
|
function fillSolid(argb) {
|
|
@@ -313,8 +341,16 @@ export async function exportValidationToExcel(records, userPath) {
|
|
|
313
341
|
buildSummarySheet(wb, records);
|
|
314
342
|
buildDetailSheet(wb, records);
|
|
315
343
|
buildChecklistSheet(wb, records);
|
|
316
|
-
const
|
|
317
|
-
await
|
|
344
|
+
const dir = downloadsDir();
|
|
345
|
+
await mkdir(dir, { recursive: true }); // 다운로드 폴더만 없으면 만든다
|
|
346
|
+
const { name, relocated } = toFileName(userPath);
|
|
347
|
+
const data = Buffer.from(await wb.xlsx.writeBuffer());
|
|
348
|
+
const outPath = await writeNoOverwrite(dir, name, data);
|
|
349
|
+
const notes = [];
|
|
350
|
+
if (relocated)
|
|
351
|
+
notes.push("요청한 위치 대신 다운로드 폴더에 저장했습니다(다운로드 폴더에만 저장 가능).");
|
|
352
|
+
if (!outPath.endsWith(name))
|
|
353
|
+
notes.push(`같은 이름의 파일이 있어 새 이름으로 저장했습니다(기존 파일은 그대로 둠).`);
|
|
318
354
|
const detailRows = records.reduce((sum, r) => sum + r.specIssues.length + r.checklistRuns.length, 0);
|
|
319
|
-
return { path: outPath, recordCount: records.length, rowCount: detailRows };
|
|
355
|
+
return { path: outPath, recordCount: records.length, rowCount: detailRows, notes };
|
|
320
356
|
}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
8
8
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
9
|
import { loadDataStore } from "./data.js";
|
|
10
10
|
import { registerAllTools } from "./tools.js";
|
|
11
|
+
/** MCP initialize 응답의 instructions. 클라이언트가 연결 시점에 받아 세션 내내 참고한다.
|
|
12
|
+
* 검색 결과와 무관하게 항상 지킬 규칙만 둔다(세션마다 점유하므로 짧게).
|
|
13
|
+
* 근거: online-start·offline-start 「PAYCO 통신 방화벽 OPEN」, online-easypay orderSheetUrl. */
|
|
14
|
+
const SERVER_INSTRUCTIONS = `PAYCO 연동 코드를 생성할 때 문서 검색 결과와 무관하게 항상 지킬 것:
|
|
15
|
+
- PAYCO API(주문 예약, 결제 승인·취소 등)는 방화벽에 IP를 등록한 가맹점 서버에서만 정상 처리됩니다. 브라우저나 모바일 앱에서 직접 호출하는 코드를 만들지 마세요.
|
|
16
|
+
- 브라우저는 가맹점 서버가 주문 예약 API로 받은 결제창 URL(orderSheetUrl)을 여는 역할만 합니다.`;
|
|
11
17
|
/** package.json 의 version 을 그대로 사용한다.
|
|
12
18
|
* 하드코딩하면 배포 버전과 어긋난다(1.0.0 배포본이 0.2.0 으로 보고된 전례). */
|
|
13
19
|
async function packageVersion() {
|
|
@@ -29,7 +35,7 @@ async function main() {
|
|
|
29
35
|
const server = new McpServer({
|
|
30
36
|
name: "payco-mcp-devcenter",
|
|
31
37
|
version,
|
|
32
|
-
});
|
|
38
|
+
}, { instructions: SERVER_INSTRUCTIONS });
|
|
33
39
|
registerAllTools(server, store);
|
|
34
40
|
const transport = new StdioServerTransport();
|
|
35
41
|
await server.connect(transport);
|
package/dist/tools.js
CHANGED
|
@@ -189,15 +189,19 @@ function makeDateYmdCheck(field, allowFull = false) {
|
|
|
189
189
|
: { pass: false, message: `${allowFull ? "YYYYMMDD(8자리) 또는 YYYYMMDDHHmmss(14자리)" : "YYYYMMDD(8자리)"} 필요. 현재: '${val}'` };
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
|
+
// -- 개인정보 체크 항목 --
|
|
193
|
+
// 온라인 검수 가이드 「Request 파라미터에 개인정보가 유입되지는 않는지」 기반.
|
|
194
|
+
// 온라인·오프라인·오더 요청에는 개인정보 칸이 없어 실수 검출용으로 적용한다.
|
|
195
|
+
// 멤버십은 적립 대상 휴대폰번호·회원카드번호 등이 정상 요청값이라 적용하지 않는다.
|
|
196
|
+
const ITEM_PII = {
|
|
197
|
+
id: "common-pii",
|
|
198
|
+
category: "보안",
|
|
199
|
+
title: "개인정보 파라미터 미포함",
|
|
200
|
+
detail: "주민번호·카드번호·전화번호 등 개인정보가 request 파라미터에 유입되지 않아야 함",
|
|
201
|
+
autoCheck: autoCheckPii,
|
|
202
|
+
};
|
|
192
203
|
// -- 공통 체크 항목 --
|
|
193
204
|
const ITEMS_COMMON = [
|
|
194
|
-
{
|
|
195
|
-
id: "common-pii",
|
|
196
|
-
category: "보안",
|
|
197
|
-
title: "개인정보 파라미터 미포함",
|
|
198
|
-
detail: "주민번호·카드번호·전화번호 등 개인정보가 request 파라미터에 유입되지 않아야 함",
|
|
199
|
-
autoCheck: autoCheckPii,
|
|
200
|
-
},
|
|
201
205
|
{
|
|
202
206
|
id: "common-encoding",
|
|
203
207
|
category: "기타",
|
|
@@ -227,6 +231,7 @@ const ITEMS_COMMON = [
|
|
|
227
231
|
];
|
|
228
232
|
// -- 온라인결제 체크리스트 --
|
|
229
233
|
const CHECKLIST_ONLINE = [
|
|
234
|
+
ITEM_PII,
|
|
230
235
|
...ITEMS_COMMON,
|
|
231
236
|
{ id: "online-firewall", category: "사전준비", title: "PAYCO 방화벽 등록 완료" },
|
|
232
237
|
{ id: "online-merchant-code", category: "사전준비", title: "PAYCO 가맹점 코드 발급 완료" },
|
|
@@ -307,6 +312,7 @@ const CHECKLIST_ONLINE = [
|
|
|
307
312
|
];
|
|
308
313
|
// -- 오프라인결제 체크리스트 --
|
|
309
314
|
const CHECKLIST_OFFLINE = [
|
|
315
|
+
ITEM_PII,
|
|
310
316
|
...ITEMS_COMMON,
|
|
311
317
|
{ id: "offline-btn", category: "결제노출", title: "단말기에 PAYCO 결제 버튼 정상 노출 (디자인 가이드 준수)" },
|
|
312
318
|
{ id: "offline-receipt", category: "공통", title: "영수증 필요 정보 정상 노출" },
|
|
@@ -340,6 +346,7 @@ const CHECKLIST_OFFLINE = [
|
|
|
340
346
|
];
|
|
341
347
|
// -- 오더클라우드 체크리스트 --
|
|
342
348
|
const CHECKLIST_ORDER = [
|
|
349
|
+
ITEM_PII,
|
|
343
350
|
...ITEMS_COMMON,
|
|
344
351
|
{ id: "order-receipt", category: "공통", title: "영수증 필요 정보 정상 노출" },
|
|
345
352
|
{ id: "order-sales", category: "매출처리", title: "주문 수락 시 POS 단말기에 매출 정상 등록" },
|
|
@@ -444,6 +451,16 @@ function groupByCategory(items) {
|
|
|
444
451
|
export function registerAllTools(server, store) {
|
|
445
452
|
const slugs = store.index.categories.map((c) => c.slug);
|
|
446
453
|
const slugList = slugs.join(", ");
|
|
454
|
+
// 가이드 참고 링크: index.json 의 실제 주소를 쓴다(주소를 조립하면 ?id= 가 없어 개발자센터에서 열리지 않음).
|
|
455
|
+
// 개발자센터에 없는 문서(internal://)는 주소 대신 MCP 안에서 여는 방법을 안내한다.
|
|
456
|
+
const guideLink = (slug) => {
|
|
457
|
+
const url = store.index.categories.find((c) => c.slug === slug)?.url;
|
|
458
|
+
if (!url)
|
|
459
|
+
return `get_guide('${slug}')`;
|
|
460
|
+
return url.startsWith("internal://")
|
|
461
|
+
? `개발자센터 미게시 문서 (전체 내용: get_guide('${slug}'))`
|
|
462
|
+
: url;
|
|
463
|
+
};
|
|
447
464
|
// 1) search_devcenter ----------------------------------------------------
|
|
448
465
|
server.registerTool("search_devcenter", {
|
|
449
466
|
title: "개발자센터 검색",
|
|
@@ -462,7 +479,7 @@ export function registerAllTools(server, store) {
|
|
|
462
479
|
const snippets = snippetLines(md, query, 5);
|
|
463
480
|
if (titleHit || snippets.length > 0) {
|
|
464
481
|
let block = `## [${cat.slug}] ${cat.title}\n`;
|
|
465
|
-
block += ` ${cat.
|
|
482
|
+
block += ` ${guideLink(cat.slug)}\n`;
|
|
466
483
|
if (snippets.length > 0) {
|
|
467
484
|
for (const s of snippets)
|
|
468
485
|
block += ` > ${s}\n`;
|
|
@@ -503,7 +520,7 @@ export function registerAllTools(server, store) {
|
|
|
503
520
|
lines.push("");
|
|
504
521
|
for (const cat of store.index.categories) {
|
|
505
522
|
lines.push(`## [${cat.slug}] ${cat.title}`);
|
|
506
|
-
lines.push(` ${cat.
|
|
523
|
+
lines.push(` ${guideLink(cat.slug)}`);
|
|
507
524
|
if (cat.sections.length > 0) {
|
|
508
525
|
for (const s of cat.sections) {
|
|
509
526
|
lines.push(` - ${s.label}`);
|
|
@@ -587,7 +604,7 @@ export function registerAllTools(server, store) {
|
|
|
587
604
|
.describe("서비스 유형: online(온라인결제) | offline(오프라인결제) | order(오더클라우드) | membership(멤버십 클라우드)"),
|
|
588
605
|
},
|
|
589
606
|
}, async ({ service }) => {
|
|
590
|
-
const checklist = CHECKLISTS[service] ?? ITEMS_COMMON;
|
|
607
|
+
const checklist = CHECKLISTS[service] ?? [ITEM_PII, ...ITEMS_COMMON];
|
|
591
608
|
const label = SERVICE_LABELS[service] ?? service;
|
|
592
609
|
const autoItems = checklist.filter((c) => c.autoCheck);
|
|
593
610
|
const manualItems = checklist.filter((c) => !c.autoCheck);
|
|
@@ -624,7 +641,7 @@ export function registerAllTools(server, store) {
|
|
|
624
641
|
lines.push("");
|
|
625
642
|
}
|
|
626
643
|
const checkGuideSlug = `${service}-check`;
|
|
627
|
-
lines.push(`> 상세 검수 가이드: get_guide('${checkGuideSlug}') 또는
|
|
644
|
+
lines.push(`> 상세 검수 가이드: get_guide('${checkGuideSlug}') 또는 ${guideLink(checkGuideSlug)}`);
|
|
628
645
|
return text(lines.join("\n"));
|
|
629
646
|
});
|
|
630
647
|
// 8) validate_payload ---------------------------------------------------
|
|
@@ -699,7 +716,7 @@ export function registerAllTools(server, store) {
|
|
|
699
716
|
}
|
|
700
717
|
// --- 체크리스트 실행 ---
|
|
701
718
|
const service = serviceOf(api);
|
|
702
|
-
const checklist = CHECKLISTS[service] ?? ITEMS_COMMON;
|
|
719
|
+
const checklist = CHECKLISTS[service] ?? [ITEM_PII, ...ITEMS_COMMON];
|
|
703
720
|
const serviceLabel = SERVICE_LABELS[service] ?? service;
|
|
704
721
|
const runResults = checklist.map((item) => ({
|
|
705
722
|
item,
|
|
@@ -825,7 +842,7 @@ export function registerAllTools(server, store) {
|
|
|
825
842
|
lines.push("## API 명세 검증 ✓ — 이상 없음");
|
|
826
843
|
}
|
|
827
844
|
lines.push("");
|
|
828
|
-
lines.push(`참고 가이드:
|
|
845
|
+
lines.push(`참고 가이드: ${guideLink(spec.guide)}`);
|
|
829
846
|
lines.push("");
|
|
830
847
|
lines.push("---");
|
|
831
848
|
lines.push(`📊 **검수 결과 누적**: ${bufferSize()}건 — 검수가 끝났다면 사용자에게 **\"엑셀로 추출할까요?\"** 라고 물어보고, 원하면 \`export_validation_excel\` 도구를 호출하세요.`);
|
|
@@ -843,7 +860,8 @@ export function registerAllTools(server, store) {
|
|
|
843
860
|
path: z
|
|
844
861
|
.string()
|
|
845
862
|
.optional()
|
|
846
|
-
.describe("저장할 파일
|
|
863
|
+
.describe("저장할 파일 이름(선택, 예: '검수결과'). 항상 사용자의 다운로드 폴더에 저장되며 폴더 경로는 무시된다. " +
|
|
864
|
+
"같은 이름이 있으면 덮어쓰지 않고 ' (2)' 를 붙인다. 미지정 시 payco-validation-{timestamp}.xlsx."),
|
|
847
865
|
clearAfter: z
|
|
848
866
|
.boolean()
|
|
849
867
|
.optional()
|
|
@@ -855,7 +873,7 @@ export function registerAllTools(server, store) {
|
|
|
855
873
|
return notFound("누적된 검수 결과가 없습니다. 먼저 validate_payload 로 1건 이상 검수를 수행하세요.");
|
|
856
874
|
}
|
|
857
875
|
try {
|
|
858
|
-
const { path: outPath, recordCount, rowCount } = await exportValidationToExcel(records, path);
|
|
876
|
+
const { path: outPath, recordCount, rowCount, notes } = await exportValidationToExcel(records, path);
|
|
859
877
|
const cleared = clearAfter ? clearAllRecords() : 0;
|
|
860
878
|
const lines = [];
|
|
861
879
|
lines.push(`✅ 엑셀 추출 완료`);
|
|
@@ -864,6 +882,8 @@ export function registerAllTools(server, store) {
|
|
|
864
882
|
lines.push(`- 포함 검수 건수: ${recordCount}건`);
|
|
865
883
|
lines.push(`- 항목별 상세 행 수: ${rowCount}행`);
|
|
866
884
|
lines.push(`- 시트: 검수요약 / 항목별 상세 / 공통검수체크리스트 (3개)`);
|
|
885
|
+
for (const n of notes)
|
|
886
|
+
lines.push(`- 안내: ${n}`);
|
|
867
887
|
if (clearAfter) {
|
|
868
888
|
lines.push(`- 추출 후 버퍼 초기화: ${cleared}건 삭제됨`);
|
|
869
889
|
}
|
|
@@ -871,7 +891,7 @@ export function registerAllTools(server, store) {
|
|
|
871
891
|
lines.push(`- 누적 버퍼 유지 (다음 검수 결과도 동일 버퍼에 누적됨)`);
|
|
872
892
|
}
|
|
873
893
|
lines.push("");
|
|
874
|
-
lines.push("
|
|
894
|
+
lines.push("다운로드 폴더에서 위 파일을 열어 결과를 확인하세요.");
|
|
875
895
|
return text(lines.join("\n"));
|
|
876
896
|
}
|
|
877
897
|
catch (e) {
|
|
@@ -891,7 +911,8 @@ export function registerAllTools(server, store) {
|
|
|
891
911
|
server.registerTool("get_error_code", {
|
|
892
912
|
title: "에러코드/코드값 조회",
|
|
893
913
|
description: "PAYCO 코드정리 표에서 특정 코드 값을 조회. API 응답코드(1000, 4802...), " +
|
|
894
|
-
"결제수단/주문유형/카드사/은행코드 등 모든 코드 카테고리를 한번에 검색."
|
|
914
|
+
"결제수단/주문유형/카드사/은행코드 등 모든 코드 카테고리를 한번에 검색. " +
|
|
915
|
+
"같은 코드가 서비스마다 다른 뜻일 수 있으므로 결과의 [서비스 > 코드표] 표시로 구분해 답할 것.",
|
|
895
916
|
inputSchema: {
|
|
896
917
|
code: z
|
|
897
918
|
.string()
|
|
@@ -899,11 +920,13 @@ export function registerAllTools(server, store) {
|
|
|
899
920
|
.describe("조회할 코드 (예: '1000', 'CHECKOUT', 'CCBC', '02')"),
|
|
900
921
|
},
|
|
901
922
|
}, async ({ code }) => {
|
|
923
|
+
// 같은 코드가 서비스마다 다른 뜻일 수 있어(예: 1001 온라인/오프라인) 서비스명을 함께 표시
|
|
924
|
+
const where = (cat) => `${SERVICE_LABELS[cat.root] ?? cat.root} > ${cat.title}`;
|
|
902
925
|
const hits = [];
|
|
903
926
|
for (const cat of store.errorCodes.categories) {
|
|
904
927
|
const found = cat.items.find((it) => it.code === code);
|
|
905
928
|
if (found) {
|
|
906
|
-
hits.push(`[${cat
|
|
929
|
+
hits.push(`[${where(cat)}] ${found.code} = ${found.description}`);
|
|
907
930
|
}
|
|
908
931
|
}
|
|
909
932
|
if (hits.length === 0) {
|
|
@@ -911,7 +934,7 @@ export function registerAllTools(server, store) {
|
|
|
911
934
|
for (const cat of store.errorCodes.categories) {
|
|
912
935
|
for (const it of cat.items) {
|
|
913
936
|
if (it.code.startsWith(code) || it.description.includes(code)) {
|
|
914
|
-
partial.push(`[${cat
|
|
937
|
+
partial.push(`[${where(cat)}] ${it.code} = ${it.description}`);
|
|
915
938
|
if (partial.length >= 10)
|
|
916
939
|
break;
|
|
917
940
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nhnpayco-dev/mcp-devcenter",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "PAYCO 개발자센터 가이드 전체(온라인·오프라인·오더·멤버십·결제정산) 를 AI 개발 도구에서 바로 조회·검색할 수 있게 해주는 MCP 서버 (PAYCO Developer Center integration guide MCP server for Claude, Cursor and AI agents)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -64,5 +64,8 @@
|
|
|
64
64
|
"homepage": "https://devcenter.payco.com",
|
|
65
65
|
"bugs": {
|
|
66
66
|
"email": "dl_payco_ts@nhn.com"
|
|
67
|
+
},
|
|
68
|
+
"overrides": {
|
|
69
|
+
"uuid": "^11.1.1"
|
|
67
70
|
}
|
|
68
71
|
}
|