@koseha/api-mcp 0.0.1 → 0.0.3
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/dist/index.js +19 -22
- package/dist/resources/greeting.resource.js +9 -0
- package/dist/resources/index.js +7 -0
- package/dist/server.js +10 -0
- package/dist/swagger/swaggerLoader.js +21 -0
- package/dist/tools/add.tool.js +10 -0
- package/dist/tools/getApiDetail.tool.js +28 -0
- package/dist/tools/getApiList.tool.js +16 -0
- package/dist/tools/getSchema.tool.js +1 -0
- package/dist/tools/index.js +9 -0
- package/openapi.json +63 -0
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* MCP 서버 엔트리포인트
|
|
3
|
+
*/
|
|
2
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
server
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
contents: [{ uri: uri.href, text: `Hello, ${name}!` }],
|
|
20
|
-
}));
|
|
21
|
-
const transport = new StdioServerTransport();
|
|
22
|
-
await server.connect(transport);
|
|
23
|
-
console.log("MCP server is running via stdio.");
|
|
5
|
+
import { createServer } from "./server.js";
|
|
6
|
+
import { registerTools } from "./tools/index.js";
|
|
7
|
+
import { registerResources } from "./resources/index.js";
|
|
8
|
+
async function main() {
|
|
9
|
+
const server = createServer();
|
|
10
|
+
registerTools(server);
|
|
11
|
+
registerResources(server);
|
|
12
|
+
const transport = new StdioServerTransport();
|
|
13
|
+
await server.connect(transport);
|
|
14
|
+
// 👇 이 줄이 핵심
|
|
15
|
+
// process.stdin.resume();
|
|
16
|
+
}
|
|
17
|
+
// main().catch((err) => {
|
|
18
|
+
// process.stderr.write(err.stack + "\n");
|
|
19
|
+
// process.exit(1);
|
|
20
|
+
// });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export function registerGreetingResource(server) {
|
|
3
|
+
server.registerResource("greeting", new ResourceTemplate("greeting://{name}", { list: undefined }), {
|
|
4
|
+
title: "Greeting Resource",
|
|
5
|
+
description: "Dynamic greeting generator",
|
|
6
|
+
}, async (uri, { name }) => ({
|
|
7
|
+
contents: [{ uri: uri.href, text: `Hello, ${name}!` }],
|
|
8
|
+
}));
|
|
9
|
+
}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openapi.json 파일 읽기 + TTL 캐시
|
|
3
|
+
*/
|
|
4
|
+
import { readFile } from "fs/promises";
|
|
5
|
+
import { join, dirname } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
let cache = null;
|
|
10
|
+
let cachedAt = 0;
|
|
11
|
+
const TTL = 5 * 60 * 1000; // 5분
|
|
12
|
+
export async function loadSwagger() {
|
|
13
|
+
if (cache && Date.now() - cachedAt < TTL) {
|
|
14
|
+
return cache;
|
|
15
|
+
}
|
|
16
|
+
const openapiPath = join(__dirname, "../../openapi.json");
|
|
17
|
+
const fileContent = await readFile(openapiPath, "utf-8");
|
|
18
|
+
cache = JSON.parse(fileContent);
|
|
19
|
+
cachedAt = Date.now();
|
|
20
|
+
return cache;
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerAddTool(server) {
|
|
3
|
+
server.registerTool("add", {
|
|
4
|
+
title: "Addition Tool",
|
|
5
|
+
description: "Add two numbers",
|
|
6
|
+
inputSchema: { a: z.number(), b: z.number() },
|
|
7
|
+
}, async ({ a, b }) => ({
|
|
8
|
+
content: [{ type: "text", text: String(a + b) }],
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: API 상세 조회
|
|
3
|
+
*/
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { loadSwagger } from "../swagger/swaggerLoader.js";
|
|
6
|
+
export function registerGetApiDetail(server) {
|
|
7
|
+
server.registerTool("getApiDetail", {
|
|
8
|
+
title: "API 상세 조회",
|
|
9
|
+
description: "API 상세를 조회합니다.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
requestUrl: z.string(),
|
|
12
|
+
httpMethod: z.enum(["get", "post", "put", "delete", "patch"]),
|
|
13
|
+
},
|
|
14
|
+
}, async ({ requestUrl, httpMethod }) => {
|
|
15
|
+
if (!requestUrl || !httpMethod) {
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{ type: "text", text: "requestUrl 또는 httpMethod가 없습니다." },
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const swagger = await loadSwagger();
|
|
23
|
+
const api = swagger.paths[requestUrl][httpMethod];
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: JSON.stringify(api) }],
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: API 목록 조회
|
|
3
|
+
*/
|
|
4
|
+
import { loadSwagger } from "../swagger/swaggerLoader.js";
|
|
5
|
+
export function registerGetApiList(server) {
|
|
6
|
+
server.registerTool("getApiList", {
|
|
7
|
+
title: "API 목록 조회",
|
|
8
|
+
description: "API 목록을 조회합니다.",
|
|
9
|
+
}, async () => {
|
|
10
|
+
const swagger = await loadSwagger();
|
|
11
|
+
// paths → list 가공
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: "text", text: JSON.stringify(swagger.paths) }],
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
package/openapi.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.3",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "Swagger Petstore - OpenAPI 3.0",
|
|
5
|
+
"version": "1.0.11"
|
|
6
|
+
},
|
|
7
|
+
"servers": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://petstore3.swagger.io/api/v3"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"tags": [
|
|
13
|
+
{
|
|
14
|
+
"name": "pet",
|
|
15
|
+
"description": "당신의 애완동물에 대한 모든 것"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"paths": {
|
|
19
|
+
"/pet/{petId}/uploadImage": {
|
|
20
|
+
"post": {
|
|
21
|
+
"tags": ["pet"],
|
|
22
|
+
"summary": "이미지를 업로드합니다.",
|
|
23
|
+
"operationId": "uploadFile",
|
|
24
|
+
"parameters": [
|
|
25
|
+
{
|
|
26
|
+
"name": "petId",
|
|
27
|
+
"in": "path",
|
|
28
|
+
"description": "업데이트할 애완동물 ID",
|
|
29
|
+
"required": true,
|
|
30
|
+
"schema": {
|
|
31
|
+
"type": "integer",
|
|
32
|
+
"format": "int64"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "additionalMetadata",
|
|
37
|
+
"in": "query",
|
|
38
|
+
"description": "추가 메타데이터",
|
|
39
|
+
"required": false,
|
|
40
|
+
"schema": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"requestBody": {
|
|
46
|
+
"content": {
|
|
47
|
+
"application/octet-stream": {
|
|
48
|
+
"schema": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"format": "binary"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"responses": {
|
|
56
|
+
"200": {
|
|
57
|
+
"description": "성공적인 작업"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koseha/api-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "An API MCP based on Swagger docs",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/koseha/api-mcp#readme",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
28
|
-
"yaml": "^2.8.2",
|
|
29
28
|
"zod": "^4.2.1"
|
|
30
29
|
},
|
|
31
30
|
"devDependencies": {
|