plani-groupware-mcp
Version:
MCP server for groupware
191 lines (190 loc) • 6.69 kB
JavaScript
// MCP 서버 구현에 필요한 라이브러리 임포트
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod"; // 입력값 검증을 위한 라이브러리
// 그룹웨어 API 기본 설정
// api url 작성
const API_BASE = "http://www.naver.com";
const USER_AGENT = "groupware-app/1.0";
// 환경 변수에서 설정 가져오기
const USERNAME = process.env.GROUPWARE_USERNAME;
const PASSWORD = process.env.GROUPWARE_PASSWORD;
if (!USERNAME || !PASSWORD) {
console.error("Error: GROUPWARE_USERNAME and GROUPWARE_PASSWORD environment variables must be set");
process.exit(1);
}
// 토큰 저장소
let defaultToken = null;
// 초기 로그인 수행
async function initializeAuth() {
try {
console.error("Attempting to connect to API server...");
const loginData = await makeAPIRequest("/auth/login", "POST", {
username: USERNAME,
password: PASSWORD,
});
if (loginData && loginData.success) {
defaultToken = loginData.token;
console.error(`Successfully logged in as ${loginData.data.name}`);
return true;
}
else {
console.error("Failed to initialize authentication: Invalid credentials or server response");
return false;
}
}
catch (error) {
console.error("Error during authentication:", error);
return false;
}
}
// MCP 서버 인스턴스 생성
const server = new McpServer({
name: "groupware-mcp",
version: "1.0.16",
capabilities: {
resources: {},
tools: {},
}
});
// API 요청을 처리하는 헬퍼 함수
async function makeAPIRequest(url, method = "GET", body) {
const headers = {
"User-Agent": USER_AGENT,
"Content-Type": "application/json",
};
// 기본 토큰 사용
if (defaultToken) {
headers["Authorization"] = `Bearer ${defaultToken}`;
}
try {
console.error(`Making API request to ${API_BASE}${url}`);
const response = await fetch(`${API_BASE}${url}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
console.error(`API request failed with status ${response.status}`);
const errorText = await response.text();
console.error(`Error response: ${errorText}`);
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.error(`API request successful: ${JSON.stringify(data)}`);
return data;
}
catch (error) {
console.error("Error making API request:", error);
return null;
}
}
// 회의실 목록 조회 도구
server.tool("get-rooms", "Get list of all meeting rooms", {}, async () => {
const roomsData = await makeAPIRequest("/rooms", "GET");
if (!roomsData || !roomsData.success) {
return {
content: [
{
type: "text",
text: "Failed to retrieve rooms data. Please make sure you are logged in.",
},
],
};
}
const formattedRooms = roomsData.data.map((room) => `Room ID: ${room.room_id}\nName: ${room.name}\nLocation: ${room.location}\n---`);
const roomsText = `Available Meeting Rooms:\n\n${formattedRooms.join("\n")}`;
return {
content: [
{
type: "text",
text: roomsText,
},
],
};
});
// 회의실 예약 생성 도구
server.tool("create-reservation", "Create a new meeting room reservation", {
room_id: z.number().describe("ID of the meeting room to reserve"),
start_time: z.string().describe("Start time in ISO 8601 format (e.g. 2024-05-15T14:00:00Z)"),
end_time: z.string().describe("End time in ISO 8601 format (e.g. 2024-05-15T15:00:00Z)"),
purpose: z.string().describe("Purpose of the meeting"),
}, async ({ room_id, start_time, end_time, purpose }) => {
const reservationData = await makeAPIRequest("/reservations", "POST", {
room_id,
start_time,
end_time,
purpose,
});
if (!reservationData || !reservationData.success) {
return {
content: [
{
type: "text",
text: "Failed to create reservation. Please make sure you are logged in.",
},
],
};
}
const reservationText = `Reservation created successfully:\n\n` +
`Reservation ID: ${reservationData.data.reservation_id}\n` +
`Room ID: ${reservationData.data.room_id}\n` +
`Start Time: ${reservationData.data.start_time}\n` +
`End Time: ${reservationData.data.end_time}\n` +
`Purpose: ${reservationData.data.purpose}\n` +
`Status: ${reservationData.data.status}`;
return {
content: [
{
type: "text",
text: reservationText,
},
],
};
});
// 메인 함수: 서버 시작 및 실행
async function main() {
try {
// 초기 인증 수행
const authSuccess = await initializeAuth();
if (!authSuccess) {
console.error("Authentication failed, exiting...");
process.exit(1);
}
const transport = new StdioServerTransport();
// 서버 연결
await server.connect(transport);
console.error("Groupware MCP Server running on stdio");
// 프로세스 종료 시 정리
process.on('SIGINT', async () => {
console.error('Shutting down server...');
await transport.close();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.error('Shutting down server...');
await transport.close();
process.exit(0);
});
// 연결 유지를 위한 이벤트 루프
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', (data) => {
console.error('Received data:', data.toString());
});
process.stdin.on('end', () => {
console.error('stdin ended');
process.exit(0);
});
}
catch (error) {
console.error('Error in main():', error);
process.exit(1);
}
}
// 에러 처리와 함께 메인 함수 실행
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});