@nomadamas/k-skill 0.2.5 → 0.4.0

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.
Files changed (77) hide show
  1. package/package.json +1 -1
  2. package/skills/bok-ecos-stats/instruction.md +1 -1
  3. package/skills/bunjang-search/references/DISCLAIMER.md +23 -0
  4. package/skills/coupang-product-search/references/DISCLAIMER.md +23 -0
  5. package/skills/daangn-cars-search/references/DISCLAIMER.md +23 -0
  6. package/skills/daangn-jobs-search/references/DISCLAIMER.md +23 -0
  7. package/skills/daangn-realty-search/references/DISCLAIMER.md +23 -0
  8. package/skills/daangn-used-goods-search/references/DISCLAIMER.md +23 -0
  9. package/skills/daishin-report-search/references/DISCLAIMER.md +23 -0
  10. package/skills/daiso-product-search/references/DISCLAIMER.md +23 -0
  11. package/skills/danawa-price-search/references/DISCLAIMER.md +23 -0
  12. package/skills/delivery-tracking/references/DISCLAIMER.md +23 -0
  13. package/skills/express-bus-booking/references/DISCLAIMER.md +23 -0
  14. package/skills/fine-dust-location/skill.json +1 -7
  15. package/skills/flight-ticket-search/references/DISCLAIMER.md +23 -0
  16. package/skills/foresttrip-vacancy/references/DISCLAIMER.md +23 -0
  17. package/skills/intercity-bus-booking/references/DISCLAIMER.md +23 -0
  18. package/skills/job-posting-match/references/DISCLAIMER.md +23 -0
  19. package/skills/jobkorea-talent-search/references/DISCLAIMER.md +23 -0
  20. package/skills/k-skill-setup/skill.json +1 -7
  21. package/skills/kakao-bar-nearby/references/DISCLAIMER.md +15 -0
  22. package/skills/kakao-map/references/DISCLAIMER.md +15 -0
  23. package/skills/kakaotalk-mac/references/DISCLAIMER.md +15 -0
  24. package/skills/kbl-results/references/DISCLAIMER.md +13 -0
  25. package/skills/kbo-results/references/DISCLAIMER.md +13 -0
  26. package/skills/keris-academic-search/references/DISCLAIMER.md +13 -0
  27. package/skills/keris-academic-search/references/TRADEMARK-LEGAL-STATEMENT.md +7 -0
  28. package/skills/kleague-results/references/DISCLAIMER.md +13 -0
  29. package/skills/kopis-performance-search/references/DISCLAIMER.md +13 -0
  30. package/skills/kopis-performance-search/references/TRADEMARK-LEGAL-STATEMENT.md +7 -0
  31. package/skills/kopis-performance-search/skill.json +3 -4
  32. package/skills/korean-cinema-search/references/DISCLAIMER.md +13 -0
  33. package/skills/korean-stock-search/references/DISCLAIMER.md +14 -0
  34. package/skills/korean-stock-search/references/TRADEMARK-LEGAL-STATEMENT.md +7 -0
  35. package/skills/korean-transit-route/references/DISCLAIMER.md +13 -0
  36. package/skills/ktx-booking/instruction.md +38 -221
  37. package/skills/ktx-booking/references/AUTOMATION-LEGAL-STATEMENT.md +10 -0
  38. package/skills/ktx-booking/references/DISCLAIMER.md +14 -0
  39. package/skills/ktx-booking/scripts/ktx_booking.py +176 -1274
  40. package/skills/ktx-booking/scripts/ktx_booking.py.lock +27 -0
  41. package/skills/ktx-booking/scripts/ktx_timetable.py +141 -0
  42. package/skills/ktx-booking/skill.json +3 -11
  43. package/skills/lck-analytics/references/DISCLAIMER.md +13 -0
  44. package/skills/lotto-results/references/DISCLAIMER.md +13 -0
  45. package/skills/market-kurly-search/references/DISCLAIMER.md +13 -0
  46. package/skills/myrealtrip-search/instruction.md +3 -1
  47. package/skills/myrealtrip-search/references/DISCLAIMER.md +13 -0
  48. package/skills/myrealtrip-search/scripts/myrealtrip_mcp.py +30 -8
  49. package/skills/myrealtrip-search/scripts/test_myrealtrip_mcp.py +62 -0
  50. package/skills/naver-ad-performance/references/DISCLAIMER.md +13 -0
  51. package/skills/naver-blog-research/references/DISCLAIMER.md +13 -0
  52. package/skills/naver-news-search/references/DISCLAIMER.md +13 -0
  53. package/skills/naver-shopping-search/references/DISCLAIMER.md +13 -0
  54. package/skills/ohou-today-deal/references/DISCLAIMER.md +13 -0
  55. package/skills/olive-young-search/references/DISCLAIMER.md +13 -0
  56. package/skills/popbill/references/DISCLAIMER.md +13 -0
  57. package/skills/saramin-talent-search/references/DISCLAIMER.md +13 -0
  58. package/skills/seoul-weather-risk/instruction.md +28 -35
  59. package/skills/seoul-weather-risk/scripts/seoul_weather_risk.py +15 -68
  60. package/skills/seoul-weather-risk/skill.json +2 -2
  61. package/skills/srt-booking/instruction.md +48 -154
  62. package/skills/srt-booking/references/AUTOMATION-LEGAL-STATEMENT.md +25 -0
  63. package/skills/srt-booking/references/DISCLAIMER.md +13 -0
  64. package/skills/srt-booking/scripts/srt_booking.py +134 -235
  65. package/skills/srt-booking/scripts/srt_booking.py.lock +207 -0
  66. package/skills/srt-booking/skill.json +3 -15
  67. package/skills/store-longevity-radar/scripts/__pycache__/store_longevity_download.cpython-312.pyc +0 -0
  68. package/skills/ticket-availability/references/DISCLAIMER.md +13 -0
  69. package/skills/{toss-securities → toss-investment}/instruction.md +1 -1
  70. package/skills/toss-investment/references/DISCLAIMER.md +14 -0
  71. package/skills/{toss-securities → toss-investment}/references/TRADEMARK-LEGAL-STATEMENT.md +1 -1
  72. package/skills/{toss-securities → toss-investment}/skill.json +2 -2
  73. package/src/assemble.js +1 -1
  74. package/src/execute.js +13 -3
  75. package/skills/lovebug-report/instruction.md +0 -185
  76. package/skills/lovebug-report/skill.json +0 -9
  77. package/skills/srt-booking/scripts/srt_seats.py +0 -156
@@ -0,0 +1,27 @@
1
+ version = 1
2
+ revision = 1
3
+ requires-python = ">=3.11"
4
+
5
+ [manifest]
6
+ requirements = [{ name = "openpyxl", specifier = "==3.1.5" }]
7
+
8
+ [[package]]
9
+ name = "et-xmlfile"
10
+ version = "2.0.0"
11
+ source = { registry = "https://pypi.org/simple" }
12
+ sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234 }
13
+ wheels = [
14
+ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059 },
15
+ ]
16
+
17
+ [[package]]
18
+ name = "openpyxl"
19
+ version = "3.1.5"
20
+ source = { registry = "https://pypi.org/simple" }
21
+ dependencies = [
22
+ { name = "et-xmlfile" },
23
+ ]
24
+ sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464 }
25
+ wheels = [
26
+ { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910 },
27
+ ]
@@ -0,0 +1,141 @@
1
+ """Parse direction-aware KTX timetable sections from official workbooks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from collections.abc import Iterable
7
+ from dataclasses import dataclass
8
+ from datetime import date as calendar_date
9
+ from datetime import datetime, time
10
+
11
+ TIME_VALUE = re.compile(r"^(?:[01]\d|2[0-3]):[0-5]\d$")
12
+ TRAIN_NUMBER = re.compile(r"^\d{1,4}$")
13
+ WEEKDAY_NAMES = "월화수목금토일"
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class TimetableSection:
18
+ train_index: int
19
+ type_index: int
20
+ dep_index: int
21
+ arr_index: int
22
+ note_index: int
23
+
24
+
25
+ def normalize_station(value: object) -> str:
26
+ return re.sub(r"\s+", "", str(value or "")).replace("역", "")
27
+
28
+
29
+ def normalize_time(value: object) -> str | None:
30
+ if value is None:
31
+ return None
32
+ if isinstance(value, datetime):
33
+ return value.strftime("%H:%M")
34
+ if isinstance(value, time):
35
+ return None if value == time.min else value.strftime("%H:%M")
36
+ text = str(value).strip()
37
+ if TIME_VALUE.fullmatch(text):
38
+ return text
39
+ if re.fullmatch(r"\d{3,4}", text):
40
+ return f"{int(text) // 100:02d}:{int(text) % 100:02d}"
41
+ return None
42
+
43
+
44
+ def header_sections(values: list[str], dep: str, arr: str) -> list[TimetableSection]:
45
+ starts = [index for index, value in enumerate(values) if value == "열차번호"]
46
+ sections: list[TimetableSection] = []
47
+ for position, start in enumerate(starts):
48
+ end = starts[position + 1] if position + 1 < len(starts) else len(values)
49
+ dep_indices = [index for index in range(start, end) if values[index] == dep]
50
+ arr_indices = [index for index in range(start, end) if values[index] == arr]
51
+ if not dep_indices or not arr_indices:
52
+ continue
53
+ dep_index = dep_indices[0]
54
+ arr_index = arr_indices[0]
55
+ if dep_index >= arr_index:
56
+ continue
57
+ type_indices = [index for index in range(start, end) if values[index] == "편성"]
58
+ note_indices = [index for index in range(start, end) if values[index] == "비고"]
59
+ sections.append(
60
+ TimetableSection(
61
+ train_index=start,
62
+ type_index=type_indices[0] if type_indices else -1,
63
+ dep_index=dep_index,
64
+ arr_index=arr_index,
65
+ note_index=note_indices[0] if note_indices else -1,
66
+ )
67
+ )
68
+ return sections
69
+
70
+
71
+ def runs_on_date(value: object, requested_date: calendar_date) -> bool:
72
+ text = re.sub(r"\s+", "", str(value or ""))
73
+ if not text or "매일" in text:
74
+ return True
75
+ if text == "평일":
76
+ return requested_date.weekday() < 5
77
+ compact = re.sub(r"[,./·~\-]", "", text)
78
+ if re.fullmatch(r"[월화수목금토일]+", compact):
79
+ return WEEKDAY_NAMES[requested_date.weekday()] in compact
80
+ return True
81
+
82
+
83
+ def parse_timetable_rows(
84
+ rows: Iterable[Iterable[object]],
85
+ *,
86
+ dep: str,
87
+ arr: str,
88
+ requested_date: calendar_date,
89
+ earliest: str,
90
+ latest: str,
91
+ ) -> tuple[list[dict[str, str]], bool]:
92
+ dep_name = normalize_station(dep)
93
+ arr_name = normalize_station(arr)
94
+ sections: list[TimetableSection] = []
95
+ route_found = False
96
+ results: list[dict[str, str]] = []
97
+
98
+ for raw_row in rows:
99
+ row = list(raw_row)
100
+ normalized = [normalize_station(value) for value in row]
101
+ if "열차번호" in normalized:
102
+ sections = header_sections(normalized, dep_name, arr_name)
103
+ route_found = route_found or bool(sections)
104
+ continue
105
+ for section in sections:
106
+ indices = (
107
+ section.train_index,
108
+ section.type_index,
109
+ section.dep_index,
110
+ section.arr_index,
111
+ section.note_index,
112
+ )
113
+ if max(indices) >= len(row):
114
+ continue
115
+ train_no = str(row[section.train_index] or "").strip()
116
+ if not TRAIN_NUMBER.fullmatch(train_no):
117
+ continue
118
+ train_type = (
119
+ str(row[section.type_index] or "").strip().upper()
120
+ if section.type_index >= 0
121
+ else "KTX"
122
+ )
123
+ if "KTX" not in train_type:
124
+ continue
125
+ if section.note_index >= 0 and not runs_on_date(row[section.note_index], requested_date):
126
+ continue
127
+ dep_time = normalize_time(row[section.dep_index])
128
+ arr_time = normalize_time(row[section.arr_index])
129
+ if dep_time is None or arr_time is None or not earliest <= dep_time <= latest:
130
+ continue
131
+ results.append(
132
+ {
133
+ "train_no": train_no,
134
+ "train_type": train_type,
135
+ "dep": dep,
136
+ "arr": arr,
137
+ "dep_time": dep_time,
138
+ "arr_time": arr_time,
139
+ }
140
+ )
141
+ return results, route_found
@@ -1,16 +1,8 @@
1
1
  {
2
2
  "name": "ktx-booking",
3
- "description": "Search, reserve, inspect, and cancel KTX or Korail tickets in Korea with the korail2 + pycryptodome Python packages. Use when the user asks for KTX seats, Korail bookings, train changes, reservation status, remaining seat numbers, car-by-car seats, or power-outlet/good-seat tips. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.",
3
+ "description": "Read-only KTX operating-timetable lookup from official Korail public XLSX attachments. No login, internal mobile API, anti-bot bypass, live seat availability, reservation, or payment.",
4
4
  "profiles": [
5
- "vault",
6
- "browser",
7
- "action:booking"
5
+ "lookup"
8
6
  ],
9
- "frontmatter": "name: ktx-booking\ndescription: Search, reserve, inspect, and cancel KTX or Korail tickets in Korea with the korail2 + pycryptodome Python packages. Use when the user asks for KTX seats, Korail bookings, train changes, reservation status, remaining seat numbers, car-by-car seats, or power-outlet/good-seat tips. 돌쇠에서는 공식 표면을 통한 후속 액션까지 진행한다.\nlicense: MIT\nmetadata:\n category: travel\n locale: ko-KR\n phase: v1",
10
- "bundle": [
11
- {
12
- "from": "scripts/ktx_booking.py",
13
- "to": "scripts/ktx_booking.py"
14
- }
15
- ]
7
+ "frontmatter": "name: ktx-booking\ndescription: Read-only KTX operating-timetable lookup from official Korail public XLSX attachments. No login, internal mobile API, anti-bot bypass, live seat availability, reservation, or payment.\nlicense: MIT\nmetadata:\n category: travel\n locale: ko-KR\n phase: v1"
16
8
  }
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `lck-analytics`
2
+
3
+ 이 스킬은 Riot Games·LCK 또는 데이터 제공자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 경기·리그 분석 기능과 조회 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, 크롤링을 일반적으로 허용하지 않습니다. [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)의 데이터베이스 권리와 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)의 서비스 장애·영업 방해 책임은 별도입니다.
8
+
9
+ - 공개 경기정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 별도 경기 DB 구축·재배포, 방송·영상·이미지 복제를 하지 않습니다.
11
+ - Riot/LCK 데이터 정책과 attribution 요구를 지키고 접근통제·차단을 우회하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `lotto-results`
2
+
3
+ 이 스킬은 동행복권 또는 복권 운영기관의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 당첨결과 조회 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)의 데이터베이스 권리와 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 당첨정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용하고 조직적·대량 크롤링이나 별도 DB 구축을 하지 않습니다.
10
+ - 사용자 번호를 불필요하게 보관·공유하지 않고 복권 구매·대리행위를 수행하지 않습니다.
11
+ - 접근통제·차단·rate limit을 우회하거나 정상 서비스를 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `market-kurly-search`
2
+
3
+ 이 스킬은 컬리·마켓컬리 또는 판매자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 상품 조회 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)의 상품 DB 권리와 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 상품정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 상품 DB 구축·재판매, 이미지·상세설명 원본 재배포를 하지 않습니다.
11
+ - 접근통제·CAPTCHA·차단·rate limit을 우회하거나 정상 영업을 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -57,6 +57,8 @@ Python MCP SDK가 필요하다. 없으면 설치한다.
57
57
  python3 -m pip install mcp
58
58
  ```
59
59
 
60
+ 래퍼는 MCP Python SDK 1.x(`streamablehttp_client`)와 2.x(`streamable_http_client`) 모두에서 동작한다. `pip install mcp`는 최신 2.x를 설치한다.
61
+
60
62
  기본 엔드포인트는 공식 문서의 URL이다. 필요할 때만 환경변수로 바꾼다.
61
63
 
62
64
  ```bash
@@ -221,7 +223,7 @@ npx -y @nomadamas/k-skill@0 exec myrealtrip-search scripts/myrealtrip_mcp.py --
221
223
 
222
224
  ## 실패 상황과 대응
223
225
 
224
- - `Python package 'mcp' is required`: `python3 -m pip install mcp` 후 재시도한다.
226
+ - `Python 패키지 'mcp' 필요합니다` 또는 ImportError 내용이 함께 나온 경우: `python3 -m pip install mcp` 후 재시도한다. 패키지는 설치됐는데 심볼을 못 찾는다면 SDK 1.x/2.x 호환 래퍼가 최신 k-skill인지 확인한다.
225
227
  - MCP 엔드포인트 연결 실패: `MYREALTRIP_MCP_ENDPOINT` 오타, 네트워크, upstream 장애를 확인한다.
226
228
  - 빈 결과: 날짜/지역/인원/공항코드를 바꿔 재검색한다.
227
229
  - 항공 검색 실패: 국내/국제 도구 선택이 맞는지 확인한다. 해외 목적지는 반드시 `searchInternationalFlights`다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `myrealtrip-search`
2
+
3
+ 이 스킬은 마이리얼트립·항공사·숙박업체·예약 제공자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 여행상품 조회·예약 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, 크롤링·예약 선점·결제 자동화를 일반적으로 허용하지 않습니다. [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)과 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 여행정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 별도 DB 구축, 반복 예약 선점이나 구매 자동화에 사용하지 않습니다.
11
+ - 접근통제·CAPTCHA·차단·rate limit을 우회하거나 예약 서비스의 정상 영업을 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -11,6 +11,7 @@ from __future__ import annotations
11
11
 
12
12
  import argparse
13
13
  import asyncio
14
+ import importlib
14
15
  import json
15
16
  import os
16
17
  import sys
@@ -107,18 +108,37 @@ def parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace:
107
108
  return parser.parse_args(argv)
108
109
 
109
110
 
110
- async def _run_mcp_once(endpoint: str, command: str, tool: str | None, arguments: dict[str, Any] | None) -> Any:
111
+ def tool_input_schema(tool: Any) -> dict[str, Any]:
112
+ schema = getattr(tool, "input_schema", None) or getattr(tool, "inputSchema", None) or {}
113
+ return schema if isinstance(schema, dict) else {}
114
+
115
+
116
+ def load_mcp_client() -> tuple[Any, Any]:
111
117
  try:
112
- from mcp import ClientSession
113
- from mcp.client.streamable_http import streamablehttp_client
114
- except Exception as exc: # pragma: no cover - environment dependent
118
+ mcp = importlib.import_module("mcp")
119
+ http = importlib.import_module("mcp.client.streamable_http")
120
+ except ImportError as exc:
115
121
  raise MyRealTripMcpError(
116
- "Python 패키지 'mcp'가 필요합니다. 다음 명령으로 설치하세요: python3 -m pip install mcp"
122
+ "Python 패키지 'mcp'가 필요합니다. 다음 명령으로 설치하세요: python3 -m pip install mcp "
123
+ f"({type(exc).__name__}: {exc})"
117
124
  ) from exc
118
125
 
126
+ client_session = getattr(mcp, "ClientSession", None)
127
+ streamable = getattr(http, "streamable_http_client", None) or getattr(http, "streamablehttp_client", None)
128
+ if client_session is None or streamable is None:
129
+ raise MyRealTripMcpError(
130
+ "설치된 'mcp' 패키지에서 Streamable HTTP 클라이언트를 찾을 수 없습니다. "
131
+ "다음 명령으로 재설치하세요: python3 -m pip install mcp"
132
+ )
133
+ return client_session, streamable
134
+
135
+
136
+ async def _run_mcp_once(endpoint: str, command: str, tool: str | None, arguments: dict[str, Any] | None) -> Any:
137
+ client_session, streamable_http_client = load_mcp_client()
138
+
119
139
  try:
120
- async with streamablehttp_client(endpoint) as (read_stream, write_stream, _):
121
- async with ClientSession(read_stream, write_stream) as session:
140
+ async with streamable_http_client(endpoint) as (read_stream, write_stream, _):
141
+ async with client_session(read_stream, write_stream) as session:
122
142
  await session.initialize()
123
143
  if command == "tools":
124
144
  result = await session.list_tools()
@@ -126,12 +146,14 @@ async def _run_mcp_once(endpoint: str, command: str, tool: str | None, arguments
126
146
  {
127
147
  "name": item.name,
128
148
  "description": item.description,
129
- "inputSchema": item.inputSchema,
149
+ "inputSchema": tool_input_schema(item),
130
150
  }
131
151
  for item in result.tools
132
152
  ]
133
153
  if command == "call" and tool:
134
154
  return await session.call_tool(tool, arguments or {})
155
+ except MyRealTripMcpError:
156
+ raise
135
157
  except Exception as exc:
136
158
  raise MyRealTripMcpError(f"마이리얼트립 MCP 엔드포인트 호출 실패 {endpoint}: {exc}") from exc
137
159
 
@@ -2,6 +2,7 @@ import argparse
2
2
  import asyncio
3
3
  import importlib.util
4
4
  import pathlib
5
+ import types
5
6
  import unittest
6
7
  from unittest import mock
7
8
 
@@ -95,5 +96,66 @@ class TimeoutTest(unittest.TestCase):
95
96
  )
96
97
 
97
98
 
99
+ class McpSdkCompatTest(unittest.TestCase):
100
+ def test_tool_input_schema_accepts_v1_and_v2_attribute_names(self):
101
+ class V2:
102
+ input_schema = {"type": "object"}
103
+
104
+ class V1:
105
+ inputSchema = {"type": "object", "properties": {"q": {}}}
106
+
107
+ class Empty:
108
+ pass
109
+
110
+ self.assertEqual(myrealtrip_mcp.tool_input_schema(V2()), {"type": "object"})
111
+ self.assertEqual(myrealtrip_mcp.tool_input_schema(V1()), {"type": "object", "properties": {"q": {}}})
112
+ self.assertEqual(myrealtrip_mcp.tool_input_schema(Empty()), {})
113
+
114
+ def test_load_mcp_client_prefers_sdk_v2_name(self):
115
+ fake_session = object()
116
+ fake_v2 = object()
117
+ fake_mcp = types.SimpleNamespace(ClientSession=fake_session)
118
+ fake_http = types.SimpleNamespace(streamable_http_client=fake_v2, streamablehttp_client=object())
119
+
120
+ with mock.patch.object(myrealtrip_mcp.importlib, "import_module", side_effect=lambda name: fake_mcp if name == "mcp" else fake_http):
121
+ session, client = myrealtrip_mcp.load_mcp_client()
122
+
123
+ self.assertIs(session, fake_session)
124
+ self.assertIs(client, fake_v2)
125
+
126
+ def test_load_mcp_client_falls_back_to_sdk_v1_name(self):
127
+ fake_session = object()
128
+ fake_v1 = object()
129
+ fake_mcp = types.SimpleNamespace(ClientSession=fake_session)
130
+ fake_http = types.SimpleNamespace(streamablehttp_client=fake_v1)
131
+
132
+ with mock.patch.object(myrealtrip_mcp.importlib, "import_module", side_effect=lambda name: fake_mcp if name == "mcp" else fake_http):
133
+ session, client = myrealtrip_mcp.load_mcp_client()
134
+
135
+ self.assertIs(session, fake_session)
136
+ self.assertIs(client, fake_v1)
137
+
138
+ def test_load_mcp_client_includes_import_error_detail(self):
139
+ with mock.patch.object(myrealtrip_mcp.importlib, "import_module", side_effect=ImportError("No module named mcp")):
140
+ with self.assertRaisesRegex(myrealtrip_mcp.MyRealTripMcpError, "No module named mcp"):
141
+ myrealtrip_mcp.load_mcp_client()
142
+
143
+
144
+ if __name__ == "__main__":
145
+ def test_run_mcp_reports_timeout(self):
146
+ async def never_finishes(*args, **kwargs):
147
+ await asyncio.sleep(60)
148
+
149
+ with mock.patch.object(myrealtrip_mcp, "_run_mcp_once", side_effect=never_finishes):
150
+ with self.assertRaisesRegex(myrealtrip_mcp.MyRealTripMcpError, "초과"):
151
+ asyncio.run(
152
+ myrealtrip_mcp.run_mcp(
153
+ "https://example.invalid/mcp",
154
+ "tools",
155
+ timeout_seconds=0.001,
156
+ )
157
+ )
158
+
159
+
98
160
  if __name__ == "__main__":
99
161
  unittest.main()
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `naver-ad-performance`
2
+
3
+ 이 스킬은 네이버 또는 네이버 검색광고의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 광고 성과 조회 기능과 호환 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 접근에 관한 판단이며, 인증된 광고계정의 비공개 데이터에 대한 권한을 부여하지 않습니다. 공개되어 누구나 얻을 수 있는 정보의 기계적 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아니지만, 계정 데이터·API 계약·[저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)·[형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개정보 자동 수집 부분은 개인의 정보 조회용으로만 사용합니다. 광고계정 데이터는 본인 또는 정당한 권한을 받은 조직의 계정 범위에서만 조회합니다.
10
+ - 조직적·대량 크롤링이나 계정 데이터의 별도 DB 구축·외부 공유를 하지 않습니다.
11
+ - 인증·quota·접근통제·차단을 우회하거나 서비스 장애·영업 방해를 일으키지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `naver-blog-research`
2
+
3
+ 이 스킬은 네이버 또는 블로그 작성자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 블로그 검색·조사 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, 공개 게시물의 저작권까지 소멸시키지 않습니다. [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)과 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 블로그 정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 전문·이미지 다운로드 아카이브, 별도 DB 구축·재배포를 하지 않습니다.
11
+ - 결과는 요약·링크 중심으로 제공하고 접근통제·차단·rate limit을 우회하거나 정상 서비스를 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `naver-news-search`
2
+
3
+ 이 스킬은 네이버 또는 언론사의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 뉴스 검색 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, 기사 본문의 저작권까지 소멸시키지 않습니다. [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)과 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 뉴스 메타데이터 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 기사 전문·이미지 아카이브, 별도 DB 구축·재배포를 하지 않습니다.
11
+ - 제목·요약·원문 링크 중심으로 제공하고 접근통제·차단·quota를 우회하거나 정상 서비스를 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `naver-shopping-search`
2
+
3
+ 이 스킬은 네이버·네이버쇼핑 또는 판매자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 상품·가격 조회 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)의 상품 DB 권리와 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 상품정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 상품 DB 구축·재판매, 이미지·상세설명 원본 재배포를 하지 않습니다.
11
+ - 출처 링크를 유지하고 접근통제·차단·rate limit을 우회하거나 정상 영업을 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `ohou-today-deal`
2
+
3
+ 이 스킬은 오늘의집 또는 판매자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 상품·특가 조회 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)의 상품·리뷰 DB 권리와 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 상품정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 상품·리뷰 DB 구축·재판매, 이미지·상세설명 원본 재배포를 하지 않습니다.
11
+ - bot control·접근통제·차단·rate limit을 우회하거나 정상 영업을 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `olive-young-search`
2
+
3
+ 이 스킬은 CJ올리브영·올리브영 또는 판매자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 매장·상품·재고 조회 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아닌 사정을 제시했지만, [저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)의 상품 DB 권리와 [형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개 상품·재고정보 자동 수집은 반드시 개인의 정보 조회용으로만 사용합니다.
10
+ - 조직적·대량 크롤링, 상품 DB 구축·재판매, 이미지·상세설명 원본 재배포를 하지 않습니다.
11
+ - 접근통제·CAPTCHA·차단·rate limit을 우회하거나 정상 영업을 방해하지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `popbill`
2
+
3
+ 이 스킬은 팝빌 또는 관련 사업자의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 API 호환 기능과 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 접근에 관한 판단이며, 인증된 세금·계좌·메시지 데이터에 대한 권한을 부여하지 않습니다. 공개되어 누구나 얻을 수 있는 정보의 기계적 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아니지만, API 계약·개인정보·[저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)·[형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개정보 자동 수집 부분은 개인의 정보 조회용으로만 사용합니다. 비공개 사업 데이터는 본인 또는 정당한 권한을 받은 조직의 계정 범위에서만 처리합니다.
10
+ - 조직적 크롤링이나 세금문서·식별자·수신자 데이터의 별도 DB 구축·외부 공유를 하지 않습니다.
11
+ - 인증·quota·접근통제·차단을 우회하거나 서비스 장애·영업 방해를 일으키지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.
@@ -0,0 +1,13 @@
1
+ # DISCLAIMER — `saramin-talent-search`
2
+
3
+ 이 스킬은 사람인 또는 채용서비스 운영사의 공식 기능 또는 공식 지원 도구가 아니며, 공식 제휴·후원·승인·인증 또는 협업한 사실이 전혀 없습니다. 상표와 서비스명은 인재 검색 기능과 호환 대상을 설명하기 위해서만 사용합니다.
4
+
5
+ 대법원 2005. 6. 10. 선고 [2005도1637 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=83920)(소니용 리모컨 사건)은 기능 설명용 표장과 출처표시를 구별했습니다. [상표법 제2조](https://www.law.go.kr/법령/상표법/제2조), [제89조](https://www.law.go.kr/법령/상표법/제89조), [제90조](https://www.law.go.kr/법령/상표법/제90조), [제108조](https://www.law.go.kr/법령/상표법/제108조)에 따른 출처 혼동 판단은 별도입니다.
6
+
7
+ 대법원 2022. 5. 12. 선고 [2021도1533 판결](https://www.law.go.kr/LSW/precInfoP.do?precSeq=221765)은 공개정보 접근에 관한 판단이며, 인증된 후보자·이력서 개인정보에 대한 권한을 부여하지 않습니다. 공개되어 누구나 얻을 수 있는 정보의 기계적 수집만으로 곧바로 [정보통신망법 제48조](https://www.law.go.kr/법령/정보통신망이용촉진및정보보호등에관한법률/제48조) 위반이 되는 것은 아니지만, 개인정보·API 계약·[저작권법 제93조](https://www.law.go.kr/법령/저작권법/제93조)·[형법 제314조 제2항](https://www.law.go.kr/법령/형법/제314조)은 별도입니다.
8
+
9
+ - 공개정보 자동 수집 부분은 개인의 정보 조회용으로만 사용합니다. 후보자 데이터는 정당한 기업회원 권한과 채용 목적 범위에서만 일시 처리합니다.
10
+ - 조직적 크롤링, 후보자 DB 구축·외부 공유, 자동 지원·연락을 하지 않습니다.
11
+ - 인증·접근통제·차단·rate limit을 우회하거나 서비스 장애·영업 방해를 일으키지 않습니다.
12
+
13
+ 이 문서는 적법성을 보증하는 법률 자문이 아닙니다.