./lokal
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@./lokalread data/customers.csv with all NIK and phone numbers masked"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Lokal
Make AI coding agents Indonesia-ready.
Skills, an MCP server, and a privacy guard that help Claude Code, Cursor, Codex, and other agents build apps that are correct for Indonesia, while keeping your users' personal data out of the model.
Quick start · Features · Usage · Evaluation · Limitations · Bahasa Indonesia
Why Lokal?
Ask an AI agent to "build a checkout form" and you usually get an American one:
Without Lokal | With Lokal |
State and ZIP code fields | Provinsi → Kab/Kota → Kecamatan → Kelurahan/Desa from official Kemendagri data |
|
|
US phone validation |
|
"Submit", mixed Anda/kamu | "Kirim", one consistent register |
No QRIS, virtual accounts, or e-wallets | QRIS, Virtual Account, GoPay/OVO/DANA, with webhook-driven status |
Customer data sent to the LLM as-is | Masked first ( |
The second problem is easy to miss. While debugging, developers paste production logs and customer CSVs into Claude or Cursor, and national ID numbers (NIK), phone numbers, and bank accounts go straight to the model provider. Under Indonesia's personal data protection law, UU PDP (UU 27/2022), that is a real liability.
Lokal fixes both: it teaches agents Indonesian conventions, gives them accurate reference data, and puts Samaran (Indonesian for disguise) between your data and the model.
Related MCP server: Omega
Features
Indonesian conventions for agents. Money, phone numbers, NIK/NPWP, tiered addresses, WIB/WITA/WIT, local payment methods, UI copy, and UU PDP, packaged as Agent Skills.
Accurate reference data, bundled. All 38 provinces down to 83,762 villages, matching the Kemendagri 2025 decree exactly, with postal codes for every village. Public holidays and cuti bersama from the official SKB for 2026 and 2027.
Samaran masking. Replaces 25 kinds of Indonesian personal data, covering every category in UU PDP Article 4, with stable placeholders, then restores them in the model's output.
Samaran Guard. A Claude Code hook that stops prompts containing ID numbers and redirects reads of customer data files (
Read,Grep,cat,Get-Content, …) to a masked view.Works with any agent. Claude Code plugin, stdio MCP server for Cursor, Claude Desktop, VS Code, Windsurf, and Codex, plus a TypeScript library.
Local and offline. Data ships with the package. No network calls, no telemetry, and unmasking happens on your machine.
How it works
When the agent needs to look at customer data, it calls read_file_masked and sees [NAME_1], [NIK_1], [PHONE_1] instead of the real values. It can still deduplicate, join, and debug, because the same value always gets the same placeholder. When it writes results with write_file_unmasked, Samaran puts the real values back, on your machine.
Quick start
Claude Code
Installs the skills, the MCP server, and Samaran Guard in one step:
/plugin marketplace add lokal-id/lokal
/plugin install lokal@lokalclaude mcp add lokal -- npx -y @lokal-id/mcpOther MCP clients
Add to .cursor/mcp.json, claude_desktop_config.json, or ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"lokal": {
"command": "npx",
"args": ["-y", "@lokal-id/mcp"],
"env": { "LOKAL_ROOT": "/path/to/your/project" }
}
}
}Add to .vscode/mcp.json:
{
"servers": {
"lokal": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@lokal-id/mcp"]
}
}
}Add to ~/.codex/config.toml:
[mcp_servers.lokal]
command = "npx"
args = ["-y", "@lokal-id/mcp"]
env = { LOKAL_ROOT = "/path/to/your/project" }The file tools (scan_pii, read_file_masked, write_file_unmasked) can only access LOKAL_ROOT, which defaults to CLAUDE_PROJECT_DIR and then to the directory the server was started in.
Skills only, for any agent
npx skills add lokal-id/lokalThis installs lokal-indonesia and samaran with the skills CLI into Claude Code, Codex, Cursor, and the other agents it supports. Add -g to install them for your user instead of the current project.
Skills teach the agent the conventions. For accurate region, postal code, and holiday data and for masked file reads, add the MCP server as well (see above). Samaran Guard is a hook, so it comes only with the Claude Code plugin.
You can also copy the folders in skills/ by hand. They use the open Agent Skills format (SKILL.md).
Library
npm install @lokal-id/coreUsage
Library
import {
parseNik, parsePhone, formatRupiah, parseRupiah, terbilang, addWorkingDays, isWorkingDay,
} from '@lokal-id/core';
import { listWilayah, searchWilayah, wilayahName, findByPostalCode } from '@lokal-id/core/wilayah';
parseNik('3201011508950001', { lookupWilayah: wilayahName });
// { valid: true, province: 'Jawa Barat', regency: 'Kabupaten Bogor', district: 'Cibinong',
// gender: 'L', birthDate: '1995-08-15', … }
parsePhone('0812 3456 7890');
// { e164: '+6281234567890', national: '0812-3456-7890', whatsapp: '6281234567890', operator: 'Telkomsel', … }
formatRupiah(1500000); // 'Rp1.500.000'
terbilang(1500000, { currency: true }); // 'satu juta lima ratus ribu rupiah'
parseRupiah('2jtan'); // { amount: 2000000, approximate: true }
parseRupiah('sejuta setengah'); // { amount: 1500000, approximate: false }
listWilayah('32.76'); // districts (kecamatan) of Kota Depok
searchWilayah('kab. bogor')[0].code; // '32.01'
findByPostalCode('16431'); // villages that use this postal code
addWorkingDays('2026-03-17', 1); // '2026-03-25', skipping Nyepi and Lebaran
isWorkingDay('2026-12-24', { cutiBersama: false }); // true for offices that ignore cuti bersama@lokal-id/core/wilayah loads about 4.4 MB of region data and runs on Node only. The main entry point does not load it and is safe for browsers.
Samaran: mask before the LLM, restore after
import { Samaran } from '@lokal-id/core';
const samaran = new Samaran();
const { text } = samaran.mask(
'Nama: Budi Santoso, NIK 3201011508950001, refund ke rek BCA 1234567890, HP 0812-3456-7890',
);
// 'Nama: [NAME_1], NIK [NIK_1], refund ke rek BCA [BANK_ACCOUNT_1], HP [PHONE_1]'
const reply = await llm(text); // the model never sees the real values
samaran.unmask(reply); // placeholders are replaced with the original dataThe same value always maps to the same placeholder, across formats:
0812-…and+62 812…are both[PHONE_1].mode: 'partial'is meant for logs and admin screens:3201********0001,0812****7890,b***@gmail.com.Detection uses labels (
Agama: Islam,NAMA : BUDI), CSV and Excel headers (agama,diagnosa,gaji, …), JSON/YAML keys and query strings, and common phrases in free text (nama saya budi,didiagnosis TBC,gaji saya 8 juta).
Group | Types |
Identifiers |
|
Who and where |
|
General personal data |
|
Specific personal data (UU PDP Art. 4) |
|
MCP tools
Tool | What it does |
| Validate and decode a NIK: region, date of birth, sex |
| Tax IDs: 15-digit NPWP, 16-digit NPWP, or NIK as NPWP |
| Normalize numbers, display format, WhatsApp link, carrier |
|
|
| "2jtan", "goceng", "sejuta setengah" → numbers |
| Find provinces, regencies, districts, and villages with their codes |
| Child regions for cascading address dropdowns, with postal codes |
| Postal code → villages, or all postal codes in a region |
| National holidays and cuti bersama (SKB 2026, 2027) |
| Business days, SLA due dates, delivery estimates |
| Scan files and folders (text, CSV, JSON, logs, SQL, |
| Read a file, including |
| Write results with placeholders restored, on your machine |
Samaran Guard
Enabled automatically by the Claude Code plugin.
Prompts containing ID numbers (NIK, KK, NPWP, passport, SIM, NIP, bank account, BPJS, card) or labeled health, criminal, or biometric data are held before they are sent. Add
#izinkan-piito send anyway.Reads of data files (CSV, Excel, JSON, logs, SQL dumps, YAML, …) that contain personal data are blocked, and Claude is pointed to
read_file_masked. This covers theReadtool,Grepin content mode, and shell commands such ascat,head,grep,sed -n,awk,cut,Get-Content, andImport-Csv | Select-Object.Only what would be printed counts.
head -1 data.csv(the header),wc -l,grep -c, andsort data.csv > out.csvstill run.Not blocked: source code, where sample numbers are normal and the agent must be able to read them, and scripts run on data files (
node process.js data.csv), which is how data gets processed without being shown to the model.List files that contain fake data (fixtures, seeders) in
.samaranignore:test/fixtures/ database/seeders/ *.example.csvSet
SAMARAN_GUARD=offto disable the guard.
Evaluation
The same vibe-coding tasks were run in real Claude Code sessions in an empty folder, with and without the Lokal plugin, three times each (npm run eval, cases in evals/cases.mjs):
Task | Without Lokal | With Lokal |
Checkout form for Indonesian customers | 16/18 (address stops at city in 2 of 3 runs) | 18/18 |
Customer-service chatbot calling the Claude API | 8/12 (data never restored in replies) | 12/12 |
Deduplicate a customer CSV | 3/6 (NIK and phone numbers sent to the model in 3/3 runs) | 6/6 (model sees placeholders only) |
SLA with the 2026 Lebaran holidays | 3/3 | 3/3 |
Total | 30/39 | 39/39 |
A fifth task, debugging an app.log that contains customer NIK, phone numbers, and emails, was added later. Without Lokal, the agent ran Get-Content app.log and the whole log reached the model. With Lokal, the agent used scan_pii → read_file_masked, and no customer data reached the model in 2 of 2 runs. The first run of this task exposed a bug where a key=value log field swallowed the next pair and leaked a phone number through the scan preview. It is fixed and covered by a regression test.
This is a small sample built around everyday tasks for Indonesian developers. Do not read it as a general benchmark.
Limitations
Detection is pattern-based and favors precision. Names are found through labels, column headers, introductions ("nama saya budi", "atas nama", "a.n.", "bernama"), and honorifics ("Pak Joko", "bapak ahmad"), including lowercase. A bare name with no cue ("tadi budi bilang …"), unusually phrased health or financial data, and children's data that is not marked as such can still slip through. Treat Samaran as a strong safety net, not a guarantee.
Tested for false positives on 12 MB of open-source code and the full text of UU 27/2022, with no high-confidence name detections. Chat name detection caught 29 of 29 test sentences with names and flagged 0 of 26 ordinary chat sentences. The sentences were written for the test suite, so accuracy on real chats may be lower.
Not every format is read. PDF, legacy
.xls, images (ID card photos, selfies), and archives are not scanned.scan_piireports them as not scanned, never as clean.NIK and NPWP checks are structural. They cannot confirm that a number is registered with Dukcapil or the tax office.
Carrier detection uses number prefixes, which match the public allocation list, including the 2025 XLSmart merger. Indonesia has no mobile number portability yet (a case is pending at the Constitutional Court, 319/PUU-XXIV/2026), so prefixes are still reliable. Landline area codes cover 19 major cities.
The guard intercepts prompts,
Read,Grep, and common shell readers. A script that deliberately prints a data file, or something likepython -c "print(open(...).read())", cannot be caught every time. Thesamaranskill steers the agent away from that.Holidays exist only for years whose SKB has been published (2026, 2027). Other years return an error, not a guess.
ChatGPT needs MCP over HTTP. This server supports stdio only for now.
Roadmap
National holidays and cuti bersama per year
Postal codes for every village
UU PDP data categories and Excel support in Samaran
Kapan: Indonesian time expressions (
besok abis maghrib,lusa jam 7an,tanggal muda) with location-based prayer timesWarga: consistent synthetic test data (NIK matching birth date and region, region-appropriate names)
PDF and
.docxsupport in SamaranFree-text address parser → region codes
HTTP transport for ChatGPT and web-based agents
Python library (
lokal-id) with the same APILocale packs for other countries (Malaysia, the Philippines, Vietnam)
Have an idea? Open an issue.
Project structure
packages/core @lokal-id/core: logic and bundled data
packages/mcp @lokal-id/mcp: MCP server and Samaran Guard
skills/ SKILL.md files for Claude, Codex, and other agents
hooks/ Claude Code hook (bundled, no dependencies)
evals/ end-to-end evaluation against real Claude Code sessions
.claude-plugin/ plugin and marketplace manifestsContributing
Contributions are welcome, in English or Bahasa Indonesia. Missed detections and false positives are especially useful. See CONTRIBUTING.md for setup and guidelines, and never include real personal data in issues or pull requests.
npm install
npm run build # core, mcp, and the bundled hook
npm test # unit tests, MCP server end to end, guard
npm run eval # real Claude Code sessions with and without the pluginSecurity
If you find a way to get personal data past Samaran or the guard, please report it privately as described in SECURITY.md rather than opening a public issue.
License
Code is released under the MIT License. Bundled data keeps its own terms:
Data | Source | License |
Regions (38 provinces, 416 regencies, 98 cities, 7,285 districts, 8,496 kelurahan, 75,266 villages) | cahyadsn/wilayah, following Kepmendagri 300.2.2-2138/2025 as amended by 300.2.2-2430/2025 | MIT |
Postal codes (83,762 of 83,762 villages) | MIT | |
Holidays and cuti bersama | SKB 3 Menteri via setneg.go.id | Public government document |
Region totals match the Kemendagri decree exactly and were last checked in October 2026; see packages/core/data/README.md to regenerate them. Every holiday date is tested against the weekday in the official announcement. The UU PDP summary in the skills was checked against the official text of UU 27/2022.
Acknowledgements
cahyadsn for maintaining open Indonesian region and postal code data.
Model Context Protocol and Agent Skills for open standards that let one toolkit work across agents.
This server cannot be deployed
Maintenance
Related MCP Connectors
Ship better Java with your coding agent.
Shared debugging memory for AI coding agents
Change-aware CI validation and affected-test guidance for coding agents.
Codebase intelligence for agents: 152 structured artifacts across 21 programs, one call.
Related MCP Servers
- AlicenseAqualityAmaintenanceA fully featured coding agent that uses symbolic operations (enabled by language servers) and works well even in large code bases. Essentially a free to use alternative to Cursor and Windsurf Agents, Cline, Roo Code and others.2928,207 PyPI30,297GPL 3.0
- AlicenseNot gradedqualityAmaintenancePersistent memory for AI coding agents2,082 PyPI222Apache 2.0
- AlicenseAqualityCmaintenanceMultilingual intelligence + memory + safety + voice layer for autonomous AI agents111MIT
- AlicenseNot gradedqualityAmaintenanceSupercharge your Agent with Semantic Code Intelligence and save 💰 in the process!662MIT