mcp-satudata-ngawi 1.0.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.
package/README.md ADDED
@@ -0,0 +1,212 @@
1
+ # MCP Satu Data Ngawi
2
+
3
+ MCP (Model Context Protocol) Server untuk mengakses data dari Portal Satu Data Kabupaten Ngawi.
4
+
5
+ ## 🌐 Portal Sumber Data
6
+
7
+ - **Website**: https://satudata.ngawikab.go.id
8
+ - **API Base**: https://apidata.kabngawi.id/api/guest
9
+
10
+ ## 📦 Instalasi
11
+
12
+ ### 1. Clone/Download Repository
13
+
14
+ ```bash
15
+ git clone <repository-url>
16
+ cd mcp-satudata-ngawi
17
+ ```
18
+
19
+ ### 2. Install Dependencies
20
+
21
+ ```bash
22
+ npm install
23
+ ```
24
+
25
+ ### 3. Build Project
26
+
27
+ ```bash
28
+ npm run build
29
+ ```
30
+
31
+ ## 🔧 Konfigurasi untuk Claude Desktop
32
+
33
+ Tambahkan konfigurasi berikut ke file `claude_desktop_config.json`:
34
+
35
+ ### Windows
36
+ Lokasi: `%APPDATA%\Claude\claude_desktop_config.json`
37
+
38
+ ### macOS
39
+ Lokasi: `~/Library/Application Support/Claude/claude_desktop_config.json`
40
+
41
+ ### Linux
42
+ Lokasi: `~/.config/Claude/claude_desktop_config.json`
43
+
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ "satudata-ngawi": {
48
+ "command": "node",
49
+ "args": ["/path/to/mcp-satudata-ngawi/dist/index.js"]
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ Atau jika menggunakan `npx`:
56
+
57
+ ```json
58
+ {
59
+ "mcpServers": {
60
+ "satudata-ngawi": {
61
+ "command": "npx",
62
+ "args": ["-y", "/path/to/mcp-satudata-ngawi"]
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ ## 🛠️ Tools yang Tersedia
69
+
70
+ ### 1. `get_kategori_sektoral`
71
+ Mendapatkan daftar kategori sektoral/sektor data.
72
+
73
+ **Parameters:**
74
+ - `page` (number, optional): Nomor halaman (default: 1)
75
+ - `per_page` (number, optional): Jumlah data per halaman (default: 100)
76
+
77
+ **Contoh Penggunaan:**
78
+ ```
79
+ Tampilkan semua kategori data di Satu Data Ngawi
80
+ ```
81
+
82
+ ### 2. `get_organisasi`
83
+ Mendapatkan daftar organisasi/OPD (Organisasi Perangkat Daerah).
84
+
85
+ **Parameters:**
86
+ - `page` (number, optional): Nomor halaman
87
+ - `per_page` (number, optional): Jumlah data per halaman
88
+ - `q` (string, optional): Kata kunci pencarian
89
+
90
+ **Contoh Penggunaan:**
91
+ ```
92
+ Cari organisasi dengan nama "Dinas Kesehatan" di Ngawi
93
+ ```
94
+
95
+ ### 3. `get_data_sektoral`
96
+ Mendapatkan daftar data sektoral/dataset.
97
+
98
+ **Parameters:**
99
+ - `page` (number, optional): Nomor halaman
100
+ - `per_page` (number, optional): Jumlah data per halaman
101
+ - `q` (string, optional): Kata kunci pencarian
102
+ - `kategori_id` (number, optional): Filter berdasarkan ID kategori
103
+ - `organisasi_id` (number, optional): Filter berdasarkan ID organisasi
104
+
105
+ **Contoh Penggunaan:**
106
+ ```
107
+ Tampilkan data sektoral tentang pertanian di Ngawi
108
+ ```
109
+
110
+ ### 4. `get_detail_data`
111
+ Mendapatkan detail lengkap dari sebuah data sektoral.
112
+
113
+ **Parameters:**
114
+ - `id` (number, required): ID data sektoral
115
+
116
+ **Contoh Penggunaan:**
117
+ ```
118
+ Lihat detail data dengan ID 123
119
+ ```
120
+
121
+ ### 5. `search_data`
122
+ Mencari data berdasarkan kata kunci.
123
+
124
+ **Parameters:**
125
+ - `keyword` (string, required): Kata kunci pencarian
126
+ - `limit` (number, optional): Jumlah hasil maksimal (default: 10)
127
+
128
+ **Contoh Penggunaan:**
129
+ ```
130
+ Cari data tentang "kemiskinan" di Satu Data Ngawi
131
+ ```
132
+
133
+ ### 6. `get_statistics`
134
+ Mendapatkan ringkasan statistik portal.
135
+
136
+ **Parameters:** Tidak ada
137
+
138
+ **Contoh Penggunaan:**
139
+ ```
140
+ Berapa total dataset yang ada di Satu Data Ngawi?
141
+ ```
142
+
143
+ ## 📚 Resources
144
+
145
+ ### `satudata://kategori`
146
+ Daftar lengkap kategori sektoral dalam format JSON.
147
+
148
+ ## 🔍 Contoh Percakapan dengan Claude
149
+
150
+ ```
151
+ User: Apa saja kategori data yang tersedia di Satu Data Ngawi?
152
+
153
+ Claude: [Menggunakan get_kategori_sektoral]
154
+ Berikut kategori data yang tersedia:
155
+ 1. Pertanian
156
+ 2. Peternakan
157
+ 3. Pendidikan
158
+ 4. Kesehatan
159
+ ... dst
160
+
161
+ User: Cari data tentang kesehatan
162
+
163
+ Claude: [Menggunakan search_data dengan keyword "kesehatan"]
164
+ Ditemukan beberapa dataset tentang kesehatan:
165
+ 1. Jumlah Puskesmas per Kecamatan
166
+ 2. Data Imunisasi Anak
167
+ ... dst
168
+
169
+ User: Lihat detail data nomor 1
170
+
171
+ Claude: [Menggunakan get_detail_data dengan ID yang sesuai]
172
+ Detail Data:
173
+ - Judul: Jumlah Puskesmas per Kecamatan
174
+ - Tahun: 2023
175
+ - Sumber: Dinas Kesehatan
176
+ ... dst
177
+ ```
178
+
179
+ ## 🏗️ Struktur Project
180
+
181
+ ```
182
+ mcp-satudata-ngawi/
183
+ ├── src/
184
+ │ └── index.ts # Source code utama
185
+ ├── dist/
186
+ │ └── index.js # Compiled JavaScript
187
+ ├── package.json
188
+ ├── tsconfig.json
189
+ └── README.md
190
+ ```
191
+
192
+ ## 📝 API Endpoints yang Digunakan
193
+
194
+ | Endpoint | Deskripsi |
195
+ |----------|-----------|
196
+ | `/kategori-sektoral` | Daftar kategori/sektor data |
197
+ | `/organisasi` | Daftar OPD/instansi |
198
+ | `/data-sektoral` | Daftar dataset |
199
+ | `/data-sektoral/{id}` | Detail dataset |
200
+
201
+ ## 🤝 Kontribusi
202
+
203
+ Silakan buat issue atau pull request jika menemukan bug atau ingin menambahkan fitur.
204
+
205
+ ## 📄 Lisensi
206
+
207
+ MIT License
208
+
209
+ ## 🙏 Credits
210
+
211
+ - Portal Satu Data Kabupaten Ngawi
212
+ - Anthropic MCP SDK
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "satudata-ngawi": {
4
+ "command": "node",
5
+ "args": ["/GANTI/DENGAN/PATH/ANDA/mcp-satudata-ngawi/dist/index.js"]
6
+ }
7
+ }
8
+ }
package/dist/CLAUDE.md ADDED
@@ -0,0 +1,7 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ *No recent activity*
7
+ </claude-mem-context>
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,315 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ // Base URL untuk API Satu Data Ngawi
6
+ const BASE_URL = "https://apidata.kabngawi.id/api/guest";
7
+ // Helper function untuk fetch API
8
+ async function fetchAPI(endpoint, params) {
9
+ const url = new URL(`${BASE_URL}${endpoint}`);
10
+ if (params) {
11
+ Object.entries(params).forEach(([key, value]) => {
12
+ url.searchParams.append(key, String(value));
13
+ });
14
+ }
15
+ const response = await fetch(url.toString(), {
16
+ headers: {
17
+ "Accept": "application/json",
18
+ "Content-Type": "application/json",
19
+ },
20
+ });
21
+ if (!response.ok) {
22
+ throw new Error(`API Error: ${response.status} ${response.statusText}`);
23
+ }
24
+ return response.json();
25
+ }
26
+ // Create MCP Server
27
+ const server = new McpServer({
28
+ name: "satudata-ngawi",
29
+ version: "1.0.0",
30
+ });
31
+ // Tool: Get Kategori Sektoral (Daftar Sektor/Kategori Data)
32
+ server.tool("get_kategori_sektoral", "Mendapatkan daftar kategori sektoral/sektor data yang tersedia di Satu Data Ngawi. Contoh: Pertanian, Kesehatan, Pendidikan, dll.", {
33
+ page: z.number().optional().default(1).describe("Nomor halaman (default: 1)"),
34
+ per_page: z.number().optional().default(100).describe("Jumlah data per halaman (default: 100)"),
35
+ }, async ({ page, per_page }) => {
36
+ try {
37
+ const result = await fetchAPI("/kategori-sektoral", {
38
+ page,
39
+ per_page,
40
+ });
41
+ const formattedData = result.data.map((k) => ({
42
+ id: k.id,
43
+ nama: k.nama,
44
+ deskripsi: k.deskripsi || "-",
45
+ }));
46
+ return {
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: JSON.stringify({
51
+ total: result.total,
52
+ halaman: result.current_page,
53
+ total_halaman: result.last_page,
54
+ kategori: formattedData,
55
+ }, null, 2),
56
+ },
57
+ ],
58
+ };
59
+ }
60
+ catch (error) {
61
+ return {
62
+ content: [
63
+ {
64
+ type: "text",
65
+ text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
66
+ },
67
+ ],
68
+ isError: true,
69
+ };
70
+ }
71
+ });
72
+ // Tool: Get Organisasi (Daftar OPD/Instansi)
73
+ server.tool("get_organisasi", "Mendapatkan daftar organisasi/OPD (Organisasi Perangkat Daerah) yang ada di Kabupaten Ngawi", {
74
+ page: z.number().optional().default(1).describe("Nomor halaman"),
75
+ per_page: z.number().optional().default(100).describe("Jumlah data per halaman"),
76
+ q: z.string().optional().default("").describe("Kata kunci pencarian nama organisasi"),
77
+ }, async ({ page, per_page, q }) => {
78
+ try {
79
+ const result = await fetchAPI("/organisasi", {
80
+ page,
81
+ per_page,
82
+ q,
83
+ });
84
+ const formattedData = result.data.map((o) => ({
85
+ id: o.id,
86
+ nama: o.nama,
87
+ singkatan: o.singkatan || "-",
88
+ }));
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: JSON.stringify({
94
+ total: result.total,
95
+ halaman: result.current_page,
96
+ total_halaman: result.last_page,
97
+ organisasi: formattedData,
98
+ }, null, 2),
99
+ },
100
+ ],
101
+ };
102
+ }
103
+ catch (error) {
104
+ return {
105
+ content: [
106
+ {
107
+ type: "text",
108
+ text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
109
+ },
110
+ ],
111
+ isError: true,
112
+ };
113
+ }
114
+ });
115
+ // Tool: Get Data Sektoral (Daftar Dataset)
116
+ server.tool("get_data_sektoral", "Mendapatkan daftar data sektoral/dataset yang tersedia. Bisa difilter berdasarkan pencarian, kategori, atau organisasi.", {
117
+ page: z.number().optional().default(1).describe("Nomor halaman"),
118
+ per_page: z.number().optional().default(20).describe("Jumlah data per halaman"),
119
+ q: z.string().optional().default("").describe("Kata kunci pencarian"),
120
+ kategori_id: z.number().optional().describe("Filter berdasarkan ID kategori sektoral"),
121
+ organisasi_id: z.number().optional().describe("Filter berdasarkan ID organisasi"),
122
+ }, async ({ page, per_page, q, kategori_id, organisasi_id }) => {
123
+ try {
124
+ const params = { page, per_page, q };
125
+ if (kategori_id)
126
+ params.kategori_sektoral_id = kategori_id;
127
+ if (organisasi_id)
128
+ params.organisasi_id = organisasi_id;
129
+ const result = await fetchAPI("/data-sektoral", params);
130
+ const formattedData = result.data.map((d) => ({
131
+ id: d.id,
132
+ judul: d.judul,
133
+ deskripsi: d.deskripsi || "-",
134
+ tahun: d.tahun || "-",
135
+ kategori: d.kategori_sektoral?.nama || "-",
136
+ organisasi: d.organisasi?.nama || "-",
137
+ sumber: d.sumber || "-",
138
+ }));
139
+ return {
140
+ content: [
141
+ {
142
+ type: "text",
143
+ text: JSON.stringify({
144
+ total: result.total,
145
+ halaman: result.current_page,
146
+ total_halaman: result.last_page,
147
+ data: formattedData,
148
+ }, null, 2),
149
+ },
150
+ ],
151
+ };
152
+ }
153
+ catch (error) {
154
+ return {
155
+ content: [
156
+ {
157
+ type: "text",
158
+ text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
159
+ },
160
+ ],
161
+ isError: true,
162
+ };
163
+ }
164
+ });
165
+ // Tool: Get Detail Data Sektoral
166
+ server.tool("get_detail_data", "Mendapatkan detail lengkap dari sebuah data sektoral berdasarkan ID, termasuk data detail/nilai-nilainya", {
167
+ id: z.number().describe("ID data sektoral yang ingin dilihat detailnya"),
168
+ }, async ({ id }) => {
169
+ try {
170
+ const result = await fetchAPI(`/data-sektoral/${id}`);
171
+ return {
172
+ content: [
173
+ {
174
+ type: "text",
175
+ text: JSON.stringify({
176
+ id: result.id,
177
+ judul: result.judul,
178
+ deskripsi: result.deskripsi || "-",
179
+ tahun: result.tahun || "-",
180
+ kategori: result.kategori_sektoral?.nama || "-",
181
+ organisasi: result.organisasi?.nama || "-",
182
+ sumber: result.sumber || "-",
183
+ data_details: result.data_details || [],
184
+ }, null, 2),
185
+ },
186
+ ],
187
+ };
188
+ }
189
+ catch (error) {
190
+ return {
191
+ content: [
192
+ {
193
+ type: "text",
194
+ text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
195
+ },
196
+ ],
197
+ isError: true,
198
+ };
199
+ }
200
+ });
201
+ // Tool: Search Data
202
+ server.tool("search_data", "Mencari data di Satu Data Ngawi berdasarkan kata kunci. Mengembalikan data sektoral yang relevan.", {
203
+ keyword: z.string().describe("Kata kunci pencarian"),
204
+ limit: z.number().optional().default(10).describe("Jumlah hasil maksimal"),
205
+ }, async ({ keyword, limit }) => {
206
+ try {
207
+ const result = await fetchAPI("/data-sektoral", {
208
+ q: keyword,
209
+ per_page: limit,
210
+ page: 1,
211
+ });
212
+ if (result.data.length === 0) {
213
+ return {
214
+ content: [
215
+ {
216
+ type: "text",
217
+ text: `Tidak ditemukan data dengan kata kunci "${keyword}"`,
218
+ },
219
+ ],
220
+ };
221
+ }
222
+ const formattedData = result.data.map((d) => ({
223
+ id: d.id,
224
+ judul: d.judul,
225
+ kategori: d.kategori_sektoral?.nama || "-",
226
+ organisasi: d.organisasi?.nama || "-",
227
+ tahun: d.tahun || "-",
228
+ }));
229
+ return {
230
+ content: [
231
+ {
232
+ type: "text",
233
+ text: JSON.stringify({
234
+ keyword,
235
+ total_ditemukan: result.total,
236
+ hasil: formattedData,
237
+ }, null, 2),
238
+ },
239
+ ],
240
+ };
241
+ }
242
+ catch (error) {
243
+ return {
244
+ content: [
245
+ {
246
+ type: "text",
247
+ text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
248
+ },
249
+ ],
250
+ isError: true,
251
+ };
252
+ }
253
+ });
254
+ // Tool: Get Statistics
255
+ server.tool("get_statistics", "Mendapatkan ringkasan statistik portal Satu Data Ngawi (jumlah kategori, organisasi, dan dataset)", {}, async () => {
256
+ try {
257
+ const [kategori, organisasi, data] = await Promise.all([
258
+ fetchAPI("/kategori-sektoral", { per_page: 1 }),
259
+ fetchAPI("/organisasi", { per_page: 1 }),
260
+ fetchAPI("/data-sektoral", { per_page: 1 }),
261
+ ]);
262
+ return {
263
+ content: [
264
+ {
265
+ type: "text",
266
+ text: JSON.stringify({
267
+ statistik: {
268
+ total_kategori_sektoral: kategori.total,
269
+ total_organisasi: organisasi.total,
270
+ total_dataset: data.total,
271
+ },
272
+ portal: "Satu Data Ngawi",
273
+ url: "https://satudata.ngawikab.go.id",
274
+ }, null, 2),
275
+ },
276
+ ],
277
+ };
278
+ }
279
+ catch (error) {
280
+ return {
281
+ content: [
282
+ {
283
+ type: "text",
284
+ text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
285
+ },
286
+ ],
287
+ isError: true,
288
+ };
289
+ }
290
+ });
291
+ // Resource: Daftar Kategori
292
+ server.resource("kategori-list", "satudata://kategori", async () => {
293
+ const result = await fetchAPI("/kategori-sektoral", {
294
+ per_page: 100,
295
+ });
296
+ return {
297
+ contents: [
298
+ {
299
+ uri: "satudata://kategori",
300
+ mimeType: "application/json",
301
+ text: JSON.stringify(result.data, null, 2),
302
+ },
303
+ ],
304
+ };
305
+ });
306
+ // Start server
307
+ async function main() {
308
+ const transport = new StdioServerTransport();
309
+ await server.connect(transport);
310
+ console.error("Satu Data Ngawi MCP Server running on stdio");
311
+ }
312
+ main().catch((error) => {
313
+ console.error("Fatal error:", error);
314
+ process.exit(1);
315
+ });
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "mcp-satudata-ngawi",
3
+ "version": "1.0.0",
4
+ "description": "MCP Server untuk mengakses data dari Portal Satu Data Kabupaten Ngawi",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "mcp-satudata-ngawi": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "claude_desktop_config.example.json"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "start": "node dist/index.js",
18
+ "dev": "tsx src/index.ts",
19
+ "prepare": "npm run build",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "satu-data",
26
+ "ngawi",
27
+ "open-data",
28
+ "indonesia",
29
+ "claude",
30
+ "anthropic"
31
+ ],
32
+ "author": "Aditya",
33
+ "license": "MIT",
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/yourusername/mcp-satudata-ngawi.git"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/yourusername/mcp-satudata-ngawi/issues"
43
+ },
44
+ "homepage": "https://github.com/yourusername/mcp-satudata-ngawi#readme",
45
+ "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.25.2",
47
+ "zod": "^4.3.5"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^25.0.9",
51
+ "tsx": "^4.21.0",
52
+ "typescript": "^5.9.3"
53
+ }
54
+ }