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 +212 -0
- package/claude_desktop_config.example.json +8 -0
- package/dist/CLAUDE.md +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +315 -0
- package/package.json +54 -0
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
|
package/dist/CLAUDE.md
ADDED
package/dist/index.d.ts
ADDED
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
|
+
}
|