mcp-server.mjs•3.1 kB
#!/usr/bin/env node
import path from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
import { config as loadEnv } from "dotenv";
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
parseNaturalQuery,
searchBizinfo,
searchBizinfoNaturalText,
formatBizinfoResults,
} from "./lib/bizinfo.js";
const __filename = fileURLToPath(import.meta.url);
loadEnv({ path: path.resolve(process.cwd(), ".env"), override: false });
const server = new McpServer({ name: "bizinfo-mcp", version: "1.0.0" });
const SearchBizinfoSchema = z.object({
region: z.string({ required_error: "region is required" }),
target: z.string().optional(),
keywords: z.string().optional(),
page: z.number().int().min(1).optional(),
page_size: z.number().int().min(1).max(50).optional(),
});
const SearchBizinfoNaturalSchema = z.object({
prompt: z.string({ required_error: "prompt is required" }),
});
server.registerTool(
"search_bizinfo",
{
description: "기업마당 지원사업 공고 검색 (예: region='광주', target='소상공인')",
inputSchema: SearchBizinfoSchema.shape,
},
async (args) => {
const params = {
region: args.region,
target: args.target,
keywords: args.keywords,
page: args.page ?? 1,
pageSize: args.page_size ?? 20,
};
const items = await searchBizinfo(params);
return {
content: [
{
type: "text",
text: formatBizinfoResults(items, params),
},
],
data: {
params,
count: items.length,
items,
},
};
}
);
server.registerTool(
"search_bizinfo_natural",
{
description: "자연어 질의를 분석해 기업마당 지원사업을 검색합니다.",
inputSchema: SearchBizinfoNaturalSchema.shape,
},
async ({ prompt }) => {
if (!prompt?.trim()) {
return {
content: [
{
type: "text",
text: "질문이 비어 있습니다.",
},
],
};
}
const params = parseNaturalQuery(prompt);
if (!params.region) {
return {
content: [
{
type: "text",
text: "지역을 인식하지 못했습니다. 예: '서울', '부산', '충청남도'",
},
],
};
}
const items = await searchBizinfo(params);
return {
content: [
{
type: "text",
text: formatBizinfoResults(items, params),
},
],
data: {
prompt,
params,
count: items.length,
items,
},
};
}
);
async function runStdio() {
const transport = new StdioServerTransport();
await server.connect(transport);
process.stdin.resume();
}
const isMainModule = process.argv[1] && path.resolve(process.argv[1]) === __filename;
if (isMainModule) {
runStdio().catch((error) => {
console.error(error);
process.exit(1);
});
}
export { runStdio };