Ssumcp

SSE

by hoeongj

124 downloads Not rated yet

About

숭실대학교의 모든 공개/개인 정보 제공과 자동화 에이전트 기능을 MCP 표준 도구로 제공하여 공개 서버

Details

Transport
SSE

Explore

- Public tools: campus meals, library books, notices, facilities search.
- Personal tools (authenticated): schedule, grades, chapel attendance, scholarships.
- One Spring Boot process serves both REST and MCP via Streamable HTTP.
- Mock connector mode enables full offline development and testing.
- Single‑flight cache and WAF cookie isolation for reliable crawling.
- Read‑only tools with explicit hints; write tools use a two‑step confirm pattern.

Setting up with Highlight

This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:

  1. Download and install Highlight from highlightai.com/download
  2. Navigate to the plugins tab and select "Add Custom Plugin"
  3. Configure the plugin with the settings below
    Plugin Name Ssumcp
    Command (node, npx, python, etc.)

    Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.

  4. Enable "Start Automatically" if you want the plugin to start when Highlight launches

From the repository

Configure your MCP client (Claude Desktop, Cursor, etc.) with the URL https://ssumcp.duckdns.org/mcp. Public tools require no authentication. For personal tools (grades, schedule, library loans), call start_auth to receive a login URL, authenticate with your Soongsil account in a browser, then pass the returned mcp_session_id in subsequent tool calls.

get_today_meal

오늘 숭실대학교 캠퍼스 식당 메뉴를 조회합니다. restaurant를 비워두면 전체 식당을 반환합니다.

get_meal_by_date

지정한 날짜의 숭실대학교 캠퍼스 식당 메뉴를 조회합니다.

get_dorm_weekly_meal

레지던스홀 기숙사 이번 주 식단을 조회합니다.

search_campus_facilities

숭실대학교 캠퍼스 내 시설(카페, 편의점, 복사실 등)을 검색합니다.

get_library_seat_status

숭실대학교 중앙도서관 층별 좌석 현황을 조회합니다 (읽기 전용).

search_library_book

숭실대학교 중앙도서관 소장 도서를 검색합니다.

get_recent_notices

숭실대학교 공지사항 최신 목록을 조회합니다.

search_notices

숭실대학교 공지사항을 키워드로 검색합니다.

list_notice_categories

숭실대학교 공지사항 카테고리 목록을 반환합니다.

get_notice_detail

공지 URL로 본문 전체 텍스트를 반환합니다. get_recent_notices나 search_notices 결과의 link 값을 전달하세요.

get_active_notices

진행중(마감 전) 공지만 반환합니다. 현재 신청 가능한 공지를 확인할 때 유용합니다.

get_department_notices

특정 학과/부서 공지만 반환합니다. 예: 컴퓨터학부, 장학팀, 소프트웨어학부.

get_auth_status

현재 MCP 세션의 provider(SAINT, LMS, LIBRARY) 연결 상태를 확인합니다.

start_auth

지정 provider의 로그인 URL을 발급합니다. 개인 도구 사용 전 호출 필요. 반환된 loginUrl을 브라우저에서 열어 로그인하세요.

logout_provider

특정 provider 연결을 해제합니다.

logout_all

MCP 세션 전체를 삭제합니다.

get_my_schedule

u-SAINT 시간표를 조회합니다. SAINT 로그인 필요.

get_my_grades

u-SAINT 성적(누적 GPA + 학기별 과목)을 조회합니다. SAINT 로그인 필요.

get_my_chapel_info

u-SAINT 채플 출석 현황을 조회합니다. SAINT 로그인 필요.

check_graduation_requirements

u-SAINT 졸업 요건 충족 여부 및 잔여 학점을 조회합니다. SAINT 로그인 필요.

get_my_scholarships

u-SAINT 장학금 수혜 내역을 조회합니다. SAINT 로그인 필요.

get_my_assignments

LMS 현재 학기 미제출 과제·퀴즈 목록을 조회합니다. LMS 로그인 필요.

get_my_library_loans

도서관 대출 현황 및 반납 기한을 조회합니다. LIBRARY 로그인 필요.

Claude Desktop / Cursor

Paste into your MCP client config file to install this server.

{
    "mcpServers": {
        "ssumcp": {
            "ssuMCP": {
                "url": "https://ssumcp.duckdns.org/mcp"
            }
        }
    }
}

McpServers

{
    "ssuMCP": {
        "url": "https://ssumcp.duckdns.org/mcp"
    }
}

CI

숭실대학교 캠퍼스 정보를 MCP(Model Context Protocol) 표준 도구로 제공하는 공개 서버.
동시에 ssuAI 웹 클라이언트를 위한 REST API 서버다.

> MCP 엔드포인트: https://ssumcp.duckdns.org/mcp

---

왜 만들었나

학식 메뉴, 도서관 좌석, 성적, 시간표처럼 매일 확인하는 정보를 매번 포털에서 찾는 게 번거로웠다. 단순히 크롤러를 만드는 대신, LLM이 직접 학교 데이터를 도구로 호출할 수 있는 MCP 서버를 만들면 챗봇·IDE·자동화 파이프라인 어디서든 재사용할 수 있겠다고 판단했다.

Claude Desktop에 연결하면 "오늘 학식 뭐야", "이번 학기 성적 알려줘" 같은 질문에 LLM이 직접 데이터를 가져와 답한다.

---

연결하기

Claude Desktop

%APPDATA%\Claude\claude_desktop_config.json (Windows) /
~/Library/Application Support/Claude/claude_desktop_config.json (macOS):

{
  "mcpServers": {
    "ssuMCP": {
      "url": "https://ssumcp.duckdns.org/mcp"
    }
  }
}

재시작 후 채팅창 도구 아이콘에서 도구 목록을 확인한다.

Cursor / 그 외 MCP 클라이언트

.cursor/mcp.json:

{
  "mcpServers": {
    "ssuMCP": {
      "url": "https://ssumcp.duckdns.org/mcp"
    }
  }
}

---

도구 목록

공개 도구 (인증 불필요)

| 도구 | 설명 |
|------|------|
| get_today_meal | 오늘 학식 메뉴 |
| get_meal_by_date | 날짜별 학식 |
| get_dorm_weekly_meal | 레지던스홀 주간 식단 |
| search_campus_facilities | 교내 시설 검색 |
| search_library_book | 중앙도서관 도서 검색 |
| get_recent_notices | 학교 공지사항 최신 목록 |
| search_notices | 공지사항 키워드 검색 |
| list_notice_categories | 공지 카테고리 목록 |
| get_notice_detail | 공지 본문 전체 조회 |
| get_active_notices | 진행 중(마감 전) 공지 |
| get_department_notices | 학과/부서별 공지 |

개인 도구 (인증 필요)

인증 흐름:

1. start_auth(provider="SAINT") → loginUrl + mcpSessionId 수신
2. loginUrl을 브라우저에서 열어 숭실대 계정 로그인
3. 이후 개인 도구 호출 시 mcp_session_id 파라미터 전달

| 도구 | provider | 설명 |
|------|----------|------|
| start_auth | — | 로그인 URL 발급 |
| get_auth_status | — | 세션 상태 확인 |
| logout_provider | — | 특정 provider 해제 |
| logout_all | — | 세션 전체 해제 |
| get_my_schedule | SAINT | 시간표 |
| get_my_grades | SAINT | 성적 |
| get_my_chapel_info | SAINT | 채플 출석 현황 |
| check_graduation_requirements | SAINT | 졸업 요건 |
| get_my_scholarships | SAINT | 장학금 수혜 내역 |
| get_my_assignments | LMS | 과제 및 퀴즈 목록 |
| get_library_seat_status | LIBRARY | 층별 좌석 현황 (2·5·6층) |
| get_my_library_loans | LIBRARY | 도서관 대출 현황 |

---

아키텍처

하나의 Spring Boot 프로세스가 REST API와 MCP 서버를 동시에 제공한다.

ssuAI (웹)          Claude Desktop / Cursor / 그 외 MCP 클라이언트
    │  REST /api/         │  MCP Streamable HTTP
    ▼                      ▼
┌──────────────────────────────────────┐
│   ssuMCP (Spring Boot 4, 단일 JVM)   │
│                                      │
│   REST Controllers   MCP Server      │
│          └──────────────┘            │
│             Service Layer            │
│         Connectors   Repositories    │
└──────────────────────────────────────┘
       │         │         │        │
    학식 사이트  도서관    LMS    u-SAINT
               (Pyxis)  (Canvas) (rusaint)

REST와 MCP 두 경로는 동일한 Service 레이어를 공유한다. MCP 도구가 별도 비즈니스 로직을 갖지 않는다.

Connector 패턴

모든 외부 시스템 호출은 인터페이스로 추상화된다.

MealConnector (interface)
├── MockMealConnector   — 고정 fixture 반환 (기본값)
└── RealMealConnector   — 실제 학식 사이트 Jsoup 파싱

@ConditionalOnProperty로 ssuai.connector.meal=mock|real에 따라 주입된다.
기본값이 mock이므로 외부 네트워크 없이 빌드·테스트·로컬 실행이 가능하다.

LLM 채팅 엔진

LlmChatService는 OpenAI 호환 API 포맷으로 10개 프로바이더에 순차 Fallback한다.

사용자 메시지
    → LlmChatService
    → LlmProvider 체인 (OpenRouter → Mistral → Groq → ...)
        Rate limit / 서버 오류 시 자동으로 다음 프로바이더로 전환
    → tool_call 발생 시
        공개 도구: McpSyncClient → 자체 /mcp (self-dogfood)
        개인 도구: 웹 세션 컨텍스트로 Service 직접 호출 (ThreadLocal)
    → 최종 응답

---

엔지니어링 노트

구현 중 부딪힌 문제와 판단 근거를 기록한다. 상세 내용은 TROUBLESHOOTING.md에 있다.

u-SAINT: SAP WebDynpro 역공학 → rusaint FFI로 전환

u-SAINT가 SAP NetWeaver WebDynpro 기반이라 sap-contextid, sap-ext-sid, SAPEVENTQUEUE 등이 stateful하게 얽혀 있다. 직접 HTTP 역공학을 8일간 시도했지만 wire-level ground truth 없이 protocol을 추측하는 방식은 한계가 명확했다.

검증된 Rust 구현체 rusaint를 JNA(Java Native Access)로 JVM에 FFI 연동하는 방향으로 전환했다. SmartID 콜백의 sToken을 rusaint withToken에 한 번만 전달하고, 결과 세션은 AES-256-GCM으로 암호화해 저장한다.

WAF 쿠키 + CookieManager 격리

대학 보안 장비(WAF)가 특정 쿠키 누락 시 세션을 익명(ANON)으로 강등한다는 사실을 브라우저 DevTools 패킷 캡처로 특정했다. 단순히 MYSAPSSO2만 전달하던 방식에서 WAF 쿠키를 함께 보존하도록 수정했다.

LMS Canvas의 5-hop SSO 체인에서는 수동 쿠키 병합 방식이 서브도메인 간 쿠키를 오염시키는 문제가 있었다. 요청마다 격리된 java.net.CookieManager를 장착한 HttpClient를 생성해 브라우저 수준의 도메인별 쿠키 격리를 구현했다.

Single-flight 캐시

SAP WebDynpro는 학기별 페이지를 이전 버튼으로 하나씩 이동해야 하는 stateful 구조다. 1시간 TTL 캐시를 두되, cold start 시 동시에 몰리는 중복 요청을 첫 요청만 upstream에 보내고 나머지는 결과를 공유하는 single-flight 패턴으로 처리했다.

Spring AI reflection workaround

McpServer.SyncSpecification.tools가 package-private final이라 tool annotation(readOnlyHint, destructiveHint) 주입 공개 API가 없었다. @Primary McpSyncServerCustomizer로 auto-configure 빈을 교체하고 reflection으로 tool list를 재구성했다. Spring AI가 공개 API를 열면 제거할 임시 bridge다.

---

보안 원칙

- 비밀 값 비로깅: 비밀번호, 세션 쿠키, JWT, API 키는 로그에 기록하지 않는다.
- 인증 경계 분리: 좌석 현황처럼 집계 데이터라도 캐시 키에 인증 여부를 포함해 익명 호출자가 인증 결과를 받지 못하게 한다.
- 읽기 전용 MCP: 20개 도구에 readOnlyHint=true, logout_
에 destructiveHint=true를 표시한다.
- Write 도구 설계 원칙: 예약·취소 같은 상태 변경 도구는 prepare_* + confirm_action 2단계 확인 패턴으로만 구현한다. (ADR 0015)

---

기술 스택

| 분류 | 기술 |
|------|------|
| 언어 / 프레임워크 | Java 21 + Kotlin 2.3, Spring Boot 4.0 |
| MCP 구현 | Spring AI 1.1 (Streamable HTTP) |
| 크롤링 | Jsoup 1.22 |
| u-SAINT 연동 | rusaint — JNA 5.18로 Rust 라이브러리를 JVM에 연결 |
| 인증 | JJWT 0.13 (HS256), AES-256-GCM |
| 테스트 | JUnit 5, MockWebServer, WireMock 3 |
| 인프라 | Oracle Cloud ARM64 · k3s · Traefik · ArgoCD · Helm · GHCR |
| DB | PostgreSQL 17 + Flyway |

---

로컬 개발

실행 (mock 모드 — 외부 네트워크 불필요)

```bash
./gradlew bootRun

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.