bps-mcp-server 0.1.0 → 0.3.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.
@@ -0,0 +1,171 @@
1
+ import { z } from "zod";
2
+ import { appendAttribution } from "../services/attribution.js";
3
+ // ========== Formatters ==========
4
+ function formatSearchResults(res) {
5
+ const lines = [];
6
+ lines.push(`## Hasil AllStats Search: "${res.query}"`);
7
+ lines.push("");
8
+ lines.push(`Ditemukan **${res.totalResults.toLocaleString("id-ID")}** hasil (halaman ${res.currentPage}/${res.totalPages})`);
9
+ lines.push("");
10
+ if (res.results.length === 0) {
11
+ lines.push("_Tidak ada hasil ditemukan._");
12
+ return lines.join("\n");
13
+ }
14
+ for (let i = 0; i < res.results.length; i++) {
15
+ const r = res.results[i];
16
+ lines.push(`### ${i + 1}. ${r.title}`);
17
+ if (r.description)
18
+ lines.push(`> ${r.description}`);
19
+ lines.push("");
20
+ lines.push(`- **Tipe:** ${r.contentType}`);
21
+ lines.push(`- **Sumber:** ${r.domain}`);
22
+ if (r.url)
23
+ lines.push(`- **URL:** ${r.url}`);
24
+ if (r.deepSearchId) {
25
+ lines.push(`- **Deep Search ID:** \`${r.deepSearchId}\` _(gunakan allstats_deep_search untuk cari teks di dalam publikasi ini)_`);
26
+ }
27
+ lines.push("");
28
+ }
29
+ if (res.currentPage < res.totalPages) {
30
+ lines.push(`---\n_Halaman ${res.currentPage} dari ${res.totalPages}. Gunakan parameter \`page\` untuk melihat halaman berikutnya._`);
31
+ }
32
+ return lines.join("\n");
33
+ }
34
+ function formatDeepSearchResults(res) {
35
+ const lines = [];
36
+ const pub = res.publication;
37
+ lines.push(`## Deep Search: "${res.query}"`);
38
+ lines.push("");
39
+ lines.push(`### Publikasi: ${pub.title}`);
40
+ if (pub.publisher)
41
+ lines.push(`**Penerbit:** ${pub.publisher}`);
42
+ if (pub.publicationUrl)
43
+ lines.push(`**URL:** ${pub.publicationUrl}`);
44
+ lines.push("");
45
+ lines.push(`Ditemukan **${res.totalMatches}** halaman cocok (halaman hasil ${res.currentPage}/${res.totalPages})`);
46
+ lines.push("");
47
+ if (res.matches.length === 0) {
48
+ lines.push("_Tidak ada halaman yang cocok ditemukan._");
49
+ return lines.join("\n");
50
+ }
51
+ for (const match of res.matches) {
52
+ lines.push(`#### Halaman ${match.pageNumber}`);
53
+ if (match.excerpt) {
54
+ lines.push(`> ${match.excerpt}`);
55
+ }
56
+ if (match.highlights.length > 0) {
57
+ lines.push(`**Kata kunci:** ${match.highlights.join(", ")}`);
58
+ }
59
+ if (match.pdfViewerUrl) {
60
+ lines.push(`**PDF:** ${match.pdfViewerUrl}`);
61
+ }
62
+ lines.push("");
63
+ }
64
+ if (res.currentPage < res.totalPages) {
65
+ lines.push(`---\n_Halaman ${res.currentPage} dari ${res.totalPages}. Gunakan parameter \`page\` untuk melihat halaman berikutnya._`);
66
+ }
67
+ return lines.join("\n");
68
+ }
69
+ // ========== Tool Registration ==========
70
+ export function registerAllStatsTools(server, allStatsClient) {
71
+ // ---------- allstats_search ----------
72
+ server.tool("allstats_search", "Pencarian konten BPS melalui AllStats Search Engine (publikasi, tabel, BRS, infografis, data mikro, glosarium, klasifikasi). Berguna untuk discovery, mencari publikasi, atau sebagai alternatif/fallback dari WebAPI search. Tidak memerlukan API key.", {
73
+ query: z.string().describe("Kata kunci pencarian"),
74
+ content: z
75
+ .enum([
76
+ "all",
77
+ "publication",
78
+ "table",
79
+ "pressrelease",
80
+ "infographic",
81
+ "microdata",
82
+ "news",
83
+ "glosarium",
84
+ "kbli2020",
85
+ "kbli2017",
86
+ "kbli2015",
87
+ "kbli2009",
88
+ ])
89
+ .default("all")
90
+ .describe("Filter tipe konten: all, publication, table, pressrelease, infographic, microdata, news, glosarium, kbli2020/2017/2015/2009"),
91
+ domain: z
92
+ .string()
93
+ .default("0000")
94
+ .describe("Kode wilayah MFD. 'all'=semua, '0000'=nasional, 2 digit=provinsi (cth: 3500=Jatim), 4 digit=kab/kota"),
95
+ page: z
96
+ .number()
97
+ .default(1)
98
+ .describe("Nomor halaman (10 hasil per halaman)"),
99
+ title_only: z
100
+ .boolean()
101
+ .default(false)
102
+ .describe("Cari di judul saja (true) atau semua field (false)"),
103
+ year_from: z
104
+ .string()
105
+ .default("all")
106
+ .describe("Filter tahun mulai ('all' atau tahun, cth: '2020')"),
107
+ year_to: z
108
+ .string()
109
+ .default("all")
110
+ .describe("Filter tahun sampai ('all' atau tahun, cth: '2024')"),
111
+ sort: z
112
+ .enum(["terbaru", "relevansi"])
113
+ .default("terbaru")
114
+ .describe("Urutan hasil: 'terbaru' (newest first) atau 'relevansi'"),
115
+ }, async ({ query, content, domain, page, title_only, year_from, year_to, sort }) => {
116
+ try {
117
+ const result = await allStatsClient.search({
118
+ query,
119
+ content,
120
+ domain,
121
+ page,
122
+ titleOnly: title_only,
123
+ yearFrom: year_from,
124
+ yearTo: year_to,
125
+ sort,
126
+ });
127
+ const text = appendAttribution(formatSearchResults(result));
128
+ return { content: [{ type: "text", text }] };
129
+ }
130
+ catch (error) {
131
+ const message = error instanceof Error
132
+ ? `Gagal melakukan pencarian AllStats: ${error.message}`
133
+ : "Terjadi kesalahan saat mengakses AllStats Search.";
134
+ return { content: [{ type: "text", text: message }], isError: true };
135
+ }
136
+ });
137
+ // ---------- allstats_deep_search ----------
138
+ server.tool("allstats_deep_search", "Full-text search di dalam isi PDF publikasi BPS. Mengembalikan halaman yang cocok beserta cuplikan teks. Dapatkan publication_id dari hasil allstats_search (field deep_search_id). Fitur unik — tidak tersedia di WebAPI. Tidak memerlukan API key.", {
139
+ query: z.string().describe("Kata kunci untuk dicari di dalam publikasi"),
140
+ publication_id: z
141
+ .string()
142
+ .regex(/^[a-f0-9]{24}$/, "Harus berupa 24 karakter hex")
143
+ .describe("ID publikasi (24 karakter hex) dari URL publikasi BPS atau dari field deep_search_id di hasil allstats_search"),
144
+ domain: z
145
+ .string()
146
+ .default("0000")
147
+ .describe("Kode wilayah MFD"),
148
+ page: z
149
+ .number()
150
+ .default(1)
151
+ .describe("Halaman hasil (bukan halaman PDF)"),
152
+ }, async ({ query, publication_id, domain, page }) => {
153
+ try {
154
+ const result = await allStatsClient.deepSearch({
155
+ query,
156
+ publicationId: publication_id,
157
+ domain,
158
+ page,
159
+ });
160
+ const text = appendAttribution(formatDeepSearchResults(result));
161
+ return { content: [{ type: "text", text }] };
162
+ }
163
+ catch (error) {
164
+ const message = error instanceof Error
165
+ ? `Gagal melakukan deep search AllStats: ${error.message}`
166
+ : "Terjadi kesalahan saat mengakses AllStats Deep Search.";
167
+ return { content: [{ type: "text", text: message }], isError: true };
168
+ }
169
+ });
170
+ }
171
+ //# sourceMappingURL=allstats.tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allstats.tools.js","sourceRoot":"","sources":["../../src/tools/allstats.tools.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { BpsClient } from "../client/bps-client.js";
3
- export declare function registerSearchTools(server: McpServer, client: BpsClient): void;
3
+ import type { AllStatsClient } from "../client/allstats-client.js";
4
+ export declare function registerSearchTools(server: McpServer, client: BpsClient, allStatsClient?: AllStatsClient): void;
4
5
  //# sourceMappingURL=search.tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.tools.d.ts","sourceRoot":"","sources":["../../src/tools/search.tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAIzD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAuB9E"}
1
+ {"version":3,"file":"search.tools.d.ts","sourceRoot":"","sources":["../../src/tools/search.tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAA0B,MAAM,8BAA8B,CAAC;AAuC3F,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,SAAS,EACjB,cAAc,CAAC,EAAE,cAAc,GAC9B,IAAI,CAuHN"}
@@ -1,22 +1,128 @@
1
1
  import { z } from "zod";
2
2
  import { appendAttribution } from "../services/attribution.js";
3
3
  import { formatErrorForUser } from "../utils/error.js";
4
- export function registerSearchTools(server, client) {
5
- server.tool("search", "Pencarian data lintas tipe di BPS. Bisa mencari tabel statis, publikasi, BRS, indikator, dan data lainnya.", {
4
+ import { BpsNotFoundError } from "../utils/error.js";
5
+ import { logger } from "../utils/logger.js";
6
+ /** Map WebAPI type names to AllStats content types */
7
+ const WEBAPI_TO_ALLSTATS_CONTENT = {
8
+ statictable: "table",
9
+ pressrelease: "pressrelease",
10
+ publication: "publication",
11
+ strategicindicator: "table",
12
+ };
13
+ function formatAllStatsFallback(res) {
14
+ const lines = [];
15
+ lines.push(`### Hasil dari AllStats Search (fallback)`);
16
+ lines.push(`Ditemukan **${res.totalResults.toLocaleString("id-ID")}** hasil via AllStats Search Engine`);
17
+ lines.push("");
18
+ for (let i = 0; i < res.results.length; i++) {
19
+ const r = res.results[i];
20
+ lines.push(`**${i + 1}. ${r.title}**`);
21
+ if (r.description)
22
+ lines.push(`> ${r.description}`);
23
+ lines.push(`- Tipe: ${r.contentType} | Sumber: ${r.domain}`);
24
+ if (r.url)
25
+ lines.push(`- URL: ${r.url}`);
26
+ if (r.deepSearchId) {
27
+ lines.push(`- Deep Search ID: \`${r.deepSearchId}\` _(gunakan allstats_deep_search untuk cari di dalam publikasi)_`);
28
+ }
29
+ lines.push("");
30
+ }
31
+ return lines.join("\n");
32
+ }
33
+ export function registerSearchTools(server, client, allStatsClient) {
34
+ server.tool("search", "Pencarian data lintas tipe di BPS. Mencari via WebAPI (tabel statis, publikasi, BRS, indikator). Jika WebAPI tidak menemukan hasil, otomatis fallback ke AllStats Search Engine untuk hasil yang lebih luas.", {
6
35
  domain: z.string().default("0000").describe("Kode domain BPS"),
7
36
  keyword: z.string().describe("Kata kunci pencarian"),
8
- type: z.string().optional().describe("Filter tipe hasil: 'statictable', 'pressrelease', 'publication', 'strategicindicator' (opsional)"),
37
+ type: z
38
+ .string()
39
+ .optional()
40
+ .describe("Filter tipe hasil: 'statictable', 'pressrelease', 'publication', 'strategicindicator' (opsional)"),
9
41
  page: z.number().optional().describe("Nomor halaman"),
10
42
  }, async ({ domain, keyword, type, page }) => {
43
+ // --- Step 1: Try WebAPI ---
44
+ let webapiResult = null;
45
+ let webapiError = null;
11
46
  try {
12
- const result = await client.search(domain, keyword, type, page);
47
+ webapiResult = await client.search(domain, keyword, type, page);
48
+ }
49
+ catch (error) {
50
+ webapiError = error;
51
+ logger.debug(`WebAPI search failed for "${keyword}": ${error instanceof Error ? error.message : "unknown"}`);
52
+ }
53
+ // Check if WebAPI returned data
54
+ const webapiHasData = webapiResult !== null &&
55
+ Array.isArray(webapiResult.data) &&
56
+ webapiResult.data.length > 0;
57
+ if (webapiHasData) {
58
+ // WebAPI returned results — use them
13
59
  const text = appendAttribution(`## Hasil Pencarian: "${keyword}"\n\n` +
14
- "```json\n" + JSON.stringify(result, null, 2) + "\n```");
60
+ "```json\n" +
61
+ JSON.stringify(webapiResult, null, 2) +
62
+ "\n```");
15
63
  return { content: [{ type: "text", text }] };
16
64
  }
17
- catch (error) {
18
- return { content: [{ type: "text", text: formatErrorForUser(error) }], isError: true };
65
+ // --- Step 2: Fallback to AllStats ---
66
+ if (allStatsClient) {
67
+ try {
68
+ const allStatsContent = type && WEBAPI_TO_ALLSTATS_CONTENT[type]
69
+ ? WEBAPI_TO_ALLSTATS_CONTENT[type]
70
+ : "all";
71
+ const allStatsResult = await allStatsClient.search({
72
+ query: keyword,
73
+ content: allStatsContent,
74
+ domain,
75
+ page: page || 1,
76
+ });
77
+ if (allStatsResult.results.length > 0) {
78
+ const parts = [];
79
+ parts.push(`## Hasil Pencarian: "${keyword}"\n`);
80
+ // Indicate fallback if WebAPI was attempted
81
+ if (webapiError) {
82
+ parts.push(`> **Catatan:** WebAPI BPS tidak tersedia (${webapiError instanceof Error ? webapiError.message : "error"}). Menampilkan hasil dari AllStats Search.\n`);
83
+ }
84
+ else if (webapiResult && !webapiHasData) {
85
+ parts.push(`> **Catatan:** WebAPI BPS tidak menemukan hasil untuk "${keyword}". Menampilkan hasil dari AllStats Search.\n`);
86
+ }
87
+ parts.push(formatAllStatsFallback(allStatsResult));
88
+ const text = appendAttribution(parts.join("\n"));
89
+ return { content: [{ type: "text", text }] };
90
+ }
91
+ }
92
+ catch (allStatsError) {
93
+ logger.debug(`AllStats fallback also failed for "${keyword}": ${allStatsError instanceof Error ? allStatsError.message : "unknown"}`);
94
+ // If both fail, return the original error
95
+ }
96
+ }
97
+ // --- Step 3: Both failed or no results ---
98
+ if (webapiError) {
99
+ // WebAPI had an error and AllStats also failed or not available
100
+ if (webapiError instanceof BpsNotFoundError) {
101
+ return {
102
+ content: [
103
+ {
104
+ type: "text",
105
+ text: `Tidak ditemukan hasil untuk "${keyword}" di WebAPI maupun AllStats Search.`,
106
+ },
107
+ ],
108
+ isError: true,
109
+ };
110
+ }
111
+ return {
112
+ content: [{ type: "text", text: formatErrorForUser(webapiError) }],
113
+ isError: true,
114
+ };
19
115
  }
116
+ // WebAPI returned empty
117
+ return {
118
+ content: [
119
+ {
120
+ type: "text",
121
+ text: `Tidak ditemukan hasil untuk "${keyword}".`,
122
+ },
123
+ ],
124
+ isError: true,
125
+ };
20
126
  });
21
127
  }
22
128
  //# sourceMappingURL=search.tools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.tools.js","sourceRoot":"","sources":["../../src/tools/search.tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,MAAiB;IACtE,MAAM,CAAC,IAAI,CACT,QAAQ,EACR,4GAA4G,EAC5G;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAC9D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kGAAkG,CAAC;QACxI,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;KACtD,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAChE,MAAM,IAAI,GAAG,iBAAiB,CAC5B,wBAAwB,OAAO,OAAO;gBACtC,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,OAAO,CACxD,CAAC;YACF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACzF,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"search.tools.js","sourceRoot":"","sources":["../../src/tools/search.tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,sDAAsD;AACtD,MAAM,0BAA0B,GAA2B;IACzD,WAAW,EAAE,OAAO;IACpB,YAAY,EAAE,cAAc;IAC5B,WAAW,EAAE,aAAa;IAC1B,kBAAkB,EAAE,OAAO;CAC5B,CAAC;AAEF,SAAS,sBAAsB,CAAC,GAA2B;IACzD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IACxD,KAAK,CAAC,IAAI,CACR,eAAe,GAAG,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,qCAAqC,CAC7F,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,WAAW,cAAc,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,CAAC,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;YACnB,KAAK,CAAC,IAAI,CACR,uBAAuB,CAAC,CAAC,YAAY,mEAAmE,CACzG,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAiB,EACjB,MAAiB,EACjB,cAA+B;IAE/B,MAAM,CAAC,IAAI,CACT,QAAQ,EACR,8MAA8M,EAC9M;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAC9D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACpD,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,kGAAkG,CACnG;QACH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;KACtD,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;QACxC,6BAA6B;QAC7B,IAAI,YAAY,GAA+B,IAAI,CAAC;QACpD,IAAI,WAAW,GAAY,IAAI,CAAC;QAEhC,IAAI,CAAC;YACH,YAAY,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,GAAG,KAAK,CAAC;YACpB,MAAM,CAAC,KAAK,CAAC,6BAA6B,OAAO,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QAC/G,CAAC;QAED,gCAAgC;QAChC,MAAM,aAAa,GACjB,YAAY,KAAK,IAAI;YACrB,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;YAChC,YAAY,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAE/B,IAAI,aAAa,EAAE,CAAC;YAClB,qCAAqC;YACrC,MAAM,IAAI,GAAG,iBAAiB,CAC5B,wBAAwB,OAAO,OAAO;gBACpC,WAAW;gBACX,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrC,OAAO,CACV,CAAC;YACF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC/C,CAAC;QAED,uCAAuC;QACvC,IAAI,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,eAAe,GACnB,IAAI,IAAI,0BAA0B,CAAC,IAAI,CAAC;oBACtC,CAAC,CAAC,0BAA0B,CAAC,IAAI,CAAC;oBAClC,CAAC,CAAC,KAAK,CAAC;gBAEZ,MAAM,cAAc,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC;oBACjD,KAAK,EAAE,OAAO;oBACd,OAAO,EAAE,eAAwB;oBACjC,MAAM;oBACN,IAAI,EAAE,IAAI,IAAI,CAAC;iBAChB,CAAC,CAAC;gBAEH,IAAI,cAAc,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtC,MAAM,KAAK,GAAa,EAAE,CAAC;oBAC3B,KAAK,CAAC,IAAI,CAAC,wBAAwB,OAAO,KAAK,CAAC,CAAC;oBAEjD,4CAA4C;oBAC5C,IAAI,WAAW,EAAE,CAAC;wBAChB,KAAK,CAAC,IAAI,CACR,6CAA6C,WAAW,YAAY,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,8CAA8C,CACxJ,CAAC;oBACJ,CAAC;yBAAM,IAAI,YAAY,IAAI,CAAC,aAAa,EAAE,CAAC;wBAC1C,KAAK,CAAC,IAAI,CACR,0DAA0D,OAAO,8CAA8C,CAChH,CAAC;oBACJ,CAAC;oBAED,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC,CAAC;oBAEnD,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;oBACjD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC/C,CAAC;YACH,CAAC;YAAC,OAAO,aAAa,EAAE,CAAC;gBACvB,MAAM,CAAC,KAAK,CACV,sCAAsC,OAAO,MAAM,aAAa,YAAY,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CACxH,CAAC;gBACF,0CAA0C;YAC5C,CAAC;QACH,CAAC;QAED,4CAA4C;QAC5C,IAAI,WAAW,EAAE,CAAC;YAChB,gEAAgE;YAChE,IAAI,WAAW,YAAY,gBAAgB,EAAE,CAAC;gBAC5C,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,gCAAgC,OAAO,qCAAqC;yBACnF;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;gBAClE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,wBAAwB;QACxB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,gCAAgC,OAAO,IAAI;iBAClD;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bps-mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for BPS (Badan Pusat Statistik) Indonesia statistics data",
5
5
  "author": "Murphi",
6
6
  "license": "MIT",
@@ -27,22 +27,29 @@
27
27
  "start": "node --env-file=.env dist/index.js",
28
28
  "lint": "eslint src/",
29
29
  "typecheck": "tsc --noEmit",
30
+ "typecheck:worker": "tsc --noEmit --project tsconfig.worker.json",
30
31
  "test": "vitest run",
31
32
  "test:unit": "vitest run tests/unit",
32
33
  "test:integration": "vitest run tests/integration",
33
- "test:watch": "vitest"
34
+ "test:watch": "vitest",
35
+ "dev:worker": "wrangler dev",
36
+ "deploy": "wrangler deploy",
37
+ "deploy:dry": "wrangler deploy --dry-run"
34
38
  },
35
39
  "dependencies": {
36
40
  "@modelcontextprotocol/sdk": "^1.12.1",
41
+ "cheerio": "^1.2.0",
37
42
  "zod": "^3.24.4"
38
43
  },
39
44
  "devDependencies": {
45
+ "@cloudflare/workers-types": "^4.20250414.0",
40
46
  "@eslint/js": "^10.0.1",
41
47
  "@types/node": "^22.15.3",
42
48
  "eslint": "^10.1.0",
43
49
  "typescript": "^5.8.3",
44
50
  "typescript-eslint": "^8.58.0",
45
- "vitest": "^3.1.2"
51
+ "vitest": "^3.1.2",
52
+ "wrangler": "^4.0.0"
46
53
  },
47
54
  "engines": {
48
55
  "node": ">=18.0.0"