somtoday-mcp 0.1.0 → 0.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "somtoday-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Unofficial read-only MCP server for the Somtoday parent portal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,10 +0,0 @@
1
- export type School = {
2
- uuid: string;
3
- naam: string;
4
- plaats?: string;
5
- };
6
- export declare const SCHOOL_LIST_SOURCES: readonly ["https://servers.somtoday.nl/organisaties.json", "https://raw.githubusercontent.com/NONtoday/organisaties.json/master/organisaties.json"];
7
- export declare function matchSchools(schools: School[], query: string): School[];
8
- export declare function parseSchools(payload: unknown): School[];
9
- export declare function fetchSchools(fetchFn?: typeof fetch): Promise<School[]>;
10
- export declare function schoolLabel(school: School): string;
@@ -1,70 +0,0 @@
1
- import { SCHOOLS_MIRROR_URL, SCHOOLS_URL } from "../constants.js";
2
- import { userAgent } from "../packageVersion.js";
3
- import { formatError } from "../errors.js";
4
- export const SCHOOL_LIST_SOURCES = [SCHOOLS_URL, SCHOOLS_MIRROR_URL];
5
- export function matchSchools(schools, query) {
6
- const needle = query.trim().toLowerCase();
7
- if (!needle) {
8
- return [];
9
- }
10
- return schools.filter((school) => school.naam.toLowerCase().includes(needle));
11
- }
12
- export function parseSchools(payload) {
13
- if (!Array.isArray(payload)) {
14
- return [];
15
- }
16
- const schools = [];
17
- for (const group of payload) {
18
- for (const item of group.instellingen ?? []) {
19
- if (item.uuid && item.naam) {
20
- schools.push({
21
- uuid: item.uuid,
22
- naam: item.naam,
23
- plaats: item.plaats,
24
- });
25
- }
26
- }
27
- }
28
- return schools;
29
- }
30
- export async function fetchSchools(fetchFn = fetch) {
31
- const errors = [];
32
- for (const url of SCHOOL_LIST_SOURCES) {
33
- try {
34
- const response = await fetchFn(url, {
35
- headers: {
36
- Accept: "application/json",
37
- "User-Agent": userAgent(),
38
- },
39
- // The official host now 301s into a Cloudflare login challenge.
40
- redirect: url === SCHOOLS_URL ? "manual" : "follow",
41
- });
42
- if (response.status >= 300 && response.status < 400) {
43
- errors.push(`${url} HTTP ${response.status}`);
44
- continue;
45
- }
46
- if (!response.ok) {
47
- errors.push(`${url} HTTP ${response.status}`);
48
- continue;
49
- }
50
- const text = await response.text();
51
- if (text.trimStart().startsWith("<")) {
52
- errors.push(`${url} returned HTML`);
53
- continue;
54
- }
55
- const schools = parseSchools(JSON.parse(text));
56
- if (schools.length === 0) {
57
- errors.push(`${url} had no schools`);
58
- continue;
59
- }
60
- return schools;
61
- }
62
- catch (error) {
63
- errors.push(`${url} ${formatError(error)}`);
64
- }
65
- }
66
- throw new Error(`School list failed. ${errors.join("; ")}`);
67
- }
68
- export function schoolLabel(school) {
69
- return school.plaats ? `${school.naam} (${school.plaats})` : school.naam;
70
- }