@koseha/api-mcp 0.0.10 → 0.0.11

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 CHANGED
@@ -45,7 +45,10 @@ Cursor 설정 파일에 추가:
45
45
  "mcpServers": {
46
46
  "api-mcp": {
47
47
  "command": "node",
48
- "args": ["./node_modules/@koseha/api-mcp/dist/index.js"]
48
+ "args": ["./node_modules/@koseha/api-mcp/dist/index.js"],
49
+ "env": {
50
+ "OPENAPI_URL": <your swagger.json url ex.'https://petstore3.swagger.io/api/v3/openapi.json'>
51
+ }
49
52
  }
50
53
  }
51
54
  }
@@ -75,7 +78,10 @@ Claude Desktop 설정 파일에 추가:
75
78
  "mcpServers": {
76
79
  "api-mcp": {
77
80
  "command": "npx",
78
- "args": ["-y", "@koseha/api-mcp"]
81
+ "args": ["-y", "@koseha/api-mcp"],
82
+ "env": {
83
+ "OPENAPI_URL": "https://api.example.com/openapi.json"
84
+ }
79
85
  }
80
86
  }
81
87
  }
@@ -88,7 +94,10 @@ Claude Desktop 설정 파일에 추가:
88
94
  "mcpServers": {
89
95
  "api-mcp": {
90
96
  "command": "node",
91
- "args": ["/path/to/api-mcp/dist/index.js"]
97
+ "args": ["/path/to/api-mcp/dist/index.js"],
98
+ "env": {
99
+ "OPENAPI_URL": "https://api.example.com/openapi.json"
100
+ }
92
101
  }
93
102
  }
94
103
  }
@@ -203,8 +212,11 @@ api-mcp/
203
212
  │ ├── resources/ # 리소스 모듈
204
213
  │ │ ├── index.ts
205
214
  │ │ └── greeting.resource.ts
206
- │ └── swagger/ # Swagger 로더
207
- └── swaggerLoader.ts
215
+ │ └── swagger/ # Swagger 로더 및 변환기
216
+ ├── swaggerLoader.ts
217
+ │ ├── apiTransformer.ts
218
+ │ ├── schemaResolver.ts
219
+ │ └── types.ts
208
220
  ├── dist/ # 빌드된 파일
209
221
  ├── openapi.json # OpenAPI 스펙 파일
210
222
  ├── package.json
@@ -212,9 +224,15 @@ api-mcp/
212
224
  └── README.md
213
225
  ```
214
226
 
215
- ## OpenAPI 스펙 파일
227
+ ## OpenAPI 스펙 설정
216
228
 
217
- 프로젝트 루트의 `openapi.json` 파일을 수정하여 사용할 API 스펙을 설정할 있습니다. 기본적으로 5분간 캐시되며, 파일 변경 자동으로 다시 로드됩니다.
229
+ `OPENAPI_URL` 환경 변수를 통해 OpenAPI 문서의 URL을 설정해야 합니다. 서버 시작 환경 변수가 설정되지 않으면 서버가 시작되지 않습니다.
230
+
231
+ 예시:
232
+
233
+ ```bash
234
+ export OPENAPI_URL=https://api.example.com/openapi.json
235
+ ```
218
236
 
219
237
  ## 의존성
220
238
 
@@ -231,13 +249,14 @@ api-mcp/
231
249
 
232
250
  ## 버전
233
251
 
234
- 현재 버전: **0.0.7**
252
+ 현재 버전: **0.0.10**
235
253
 
236
254
  ## History
237
255
 
238
- | 버전 | 날짜 | 변경사항 |
239
- | ----- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
240
- | 0.0.7 | KST 2025.12.31 | - tool 요청 openapi.json 문서의 특정 부분만 추출하여 사용하도록 변경 <br/> >> 전체 openapi.json 문서 내용이 사용되지 않도록 함. token 절약 |
256
+ | 버전 | 날짜 | 변경사항 |
257
+ | ------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
258
+ | 0.0.10 | KST 2025.12.31 | - OpenAPI 문서를 HTTP 요청으로 로드하도록 변경 <br/> - OPENAPI_URL 환경 변수 필수 검증 추가 <br/> - API 상세 조회 로직 리팩토링 (apiTransformer 모듈화) |
259
+ | 0.0.7 | KST 2025.12.31 | - tool 요청 시 openapi.json 문서의 특정 부분만 추출하여 사용하도록 변경 <br/> >> 전체 openapi.json 문서 내용이 사용되지 않도록 함. token 절약 |
241
260
 
242
261
  ## 라이선스
243
262
 
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Tool: 서비스 목록 조회
3
+ */
4
+ import { loadSwagger } from "../swagger/swaggerLoader.js";
5
+ /**
6
+ * Swagger 문서에서 모든 고유한 tags 추출
7
+ */
8
+ function extractApiGroups(swagger) {
9
+ const tags = new Set();
10
+ // tags 배열에서 추출
11
+ if (Array.isArray(swagger.tags)) {
12
+ swagger.tags.forEach((tag) => {
13
+ if (typeof tag === "string") {
14
+ tags.add(tag);
15
+ }
16
+ else if (tag?.name) {
17
+ tags.add(tag.name);
18
+ }
19
+ });
20
+ }
21
+ // paths에서 tags 추출
22
+ if (swagger.paths && typeof swagger.paths === "object") {
23
+ for (const path of Object.values(swagger.paths)) {
24
+ if (path && typeof path === "object") {
25
+ for (const method of Object.values(path)) {
26
+ if (method &&
27
+ typeof method === "object" &&
28
+ Array.isArray(method.tags)) {
29
+ method.tags.forEach((tag) => tags.add(tag));
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ return Array.from(tags).sort();
36
+ }
37
+ export function registerGetServices(server) {
38
+ server.registerTool("getServices", {
39
+ title: "서비스 목록 조회",
40
+ description: "서비스 목록을 조회합니다.",
41
+ }, async () => {
42
+ const swagger = await loadSwagger();
43
+ const apiGroups = extractApiGroups(swagger);
44
+ return {
45
+ content: [{ type: "text", text: JSON.stringify(apiGroups, null, 2) }],
46
+ };
47
+ });
48
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * 환경 변수 파싱 및 검증 유틸리티
3
+ */
4
+ /**
5
+ * URL 유효성 검증
6
+ */
7
+ function isValidUrl(url) {
8
+ try {
9
+ const parsed = new URL(url);
10
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ /**
17
+ * OPENAPI_URL 환경 변수를 파싱하여 URL 배열로 반환
18
+ *
19
+ * 지원 형식:
20
+ * 1. JSON 배열: ["https://api1.com/openapi.json","https://api2.com/openapi.json"]
21
+ * 2. 단일 문자열: https://api.example.com/openapi.json (하위 호환성)
22
+ *
23
+ * @returns URL 배열
24
+ * @throws Error - 파싱 실패 또는 유효하지 않은 URL이 있는 경우
25
+ */
26
+ export function parseOpenApiUrls(envValue) {
27
+ if (!envValue) {
28
+ throw new Error("OPENAPI_URL 환경 변수가 설정되지 않았습니다. 서버를 시작할 수 없습니다.\n" +
29
+ "환경 변수를 설정한 후 다시 시도해주세요.\n" +
30
+ '예: export OPENAPI_URL=["https://api.example.com/openapi.json"]\n' +
31
+ "또는: export OPENAPI_URL=https://api.example.com/openapi.json");
32
+ }
33
+ let urls;
34
+ // JSON 배열 형식인지 확인
35
+ const trimmed = envValue.trim();
36
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
37
+ try {
38
+ const parsed = JSON.parse(trimmed);
39
+ // 배열인지 확인
40
+ if (!Array.isArray(parsed)) {
41
+ throw new Error("OPENAPI_URL이 JSON 배열 형식이지만 배열이 아닙니다.\n" +
42
+ '올바른 형식: ["https://api1.com/openapi.json","https://api2.com/openapi.json"]');
43
+ }
44
+ // 각 요소가 문자열인지 확인
45
+ if (!parsed.every((item) => typeof item === "string")) {
46
+ throw new Error("OPENAPI_URL 배열의 모든 요소는 문자열이어야 합니다.\n" +
47
+ '올바른 형식: ["https://api1.com/openapi.json","https://api2.com/openapi.json"]');
48
+ }
49
+ urls = parsed;
50
+ }
51
+ catch (error) {
52
+ if (error instanceof SyntaxError) {
53
+ throw new Error("OPENAPI_URL의 JSON 형식이 올바르지 않습니다.\n" +
54
+ '올바른 형식: ["https://api1.com/openapi.json","https://api2.com/openapi.json"]\n' +
55
+ `오류: ${error.message}`);
56
+ }
57
+ throw error;
58
+ }
59
+ }
60
+ else {
61
+ // 단일 문자열 형식 (하위 호환성)
62
+ urls = [trimmed];
63
+ }
64
+ // 빈 배열 검증
65
+ if (urls.length === 0) {
66
+ throw new Error("OPENAPI_URL 배열이 비어있습니다. 최소 1개 이상의 URL이 필요합니다.\n" +
67
+ '올바른 형식: ["https://api1.com/openapi.json","https://api2.com/openapi.json"]');
68
+ }
69
+ // 중복 제거
70
+ urls = [...new Set(urls)];
71
+ // 각 URL 유효성 검증
72
+ const invalidUrls = [];
73
+ urls.forEach((url, index) => {
74
+ if (!isValidUrl(url)) {
75
+ invalidUrls.push(`인덱스 ${index}: "${url}"`);
76
+ }
77
+ });
78
+ if (invalidUrls.length > 0) {
79
+ throw new Error("OPENAPI_URL에 유효하지 않은 URL이 있습니다:\n" +
80
+ invalidUrls.join("\n") +
81
+ "\n\n모든 URL은 http:// 또는 https://로 시작하는 유효한 URL이어야 합니다.");
82
+ }
83
+ return urls;
84
+ }
package/package.json CHANGED
@@ -1,35 +1,35 @@
1
- {
2
- "name": "@koseha/api-mcp",
3
- "version": "0.0.10",
4
- "description": "An API MCP based on Swagger docs",
5
- "keywords": [],
6
- "homepage": "https://github.com/koseha/api-mcp#readme",
7
- "bugs": {
8
- "url": "https://github.com/koseha/api-mcp/issues"
9
- },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/koseha/api-mcp.git"
13
- },
14
- "license": "ISC",
15
- "author": "koseha",
16
- "type": "module",
17
- "main": "index.js",
18
- "bin": {
19
- "api-mcp": "dist/index.js"
20
- },
21
- "scripts": {
22
- "build": "tsc",
23
- "start": "node dist/index.js",
24
- "dev": "npm run build && npm run start"
25
- },
26
- "dependencies": {
27
- "@modelcontextprotocol/sdk": "^1.25.1",
28
- "zod": "^4.2.1"
29
- },
30
- "devDependencies": {
31
- "@types/node": "^25.0.3",
32
- "ts-node": "^10.9.2",
33
- "typescript": "^5.9.3"
34
- }
35
- }
1
+ {
2
+ "name": "@koseha/api-mcp",
3
+ "version": "0.0.11",
4
+ "description": "An API MCP based on Swagger docs",
5
+ "keywords": [],
6
+ "homepage": "https://github.com/koseha/api-mcp#readme",
7
+ "bugs": {
8
+ "url": "https://github.com/koseha/api-mcp/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/koseha/api-mcp.git"
13
+ },
14
+ "license": "ISC",
15
+ "author": "koseha",
16
+ "type": "module",
17
+ "main": "index.js",
18
+ "bin": {
19
+ "api-mcp": "dist/index.js"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "start": "node dist/index.js",
24
+ "dev": "npm run build && npm run start"
25
+ },
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.25.1",
28
+ "zod": "^4.2.1"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^25.0.3",
32
+ "ts-node": "^10.9.2",
33
+ "typescript": "^5.9.3"
34
+ }
35
+ }