Rust, Python, JavaScript, and Java libraries and MCP servers for Nigeria's NIPOST digital postcode (NDAPS): offline validation, lookup, and reverse geocoding.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add ng-postcode -- npx -y ng-postcode-mcp{
"mcpServers": {
"ng-postcode": {
"command": "npx",
"args": ["-y", "ng-postcode-mcp"]
}
}
}MCP Servers overview
# ng-postcode
[](https://github.com/Adeniyikayodee/ng-postcode/actions/workflows/ci.yml)
[](https://crates.io/crates/ng-postcode)
[](https://pypi.org/project/ng-postcode/)
[](https://pypi.org/project/ng-postcode-mcp/)
[](https://www.npmjs.com/package/ng-postcode-js)
[](https://www.npmjs.com/package/ng-postcode-mcp)
Developer tools for Nigeria's National Digital Alphanumeric Postcode System (NDAPS), the building-level postcode NIPOST launched in October 2026: libraries for Rust, Python, JavaScript, and Java, MCP servers for AI assistants on PyPI and npm, and a resolver that turns described addresses into postcodes.
A postcode has 11 characters in five segments, written `EK-01-A03-FK-01`: state, LGA, district, area and building unit.
## Packages
| Package | What it does | Install | Source |
| --- | --- | --- | --- |
| `ng-postcode` (Rust) | Parse, validate and format codes offline; client for the postcode.gov.ng API | `cargo add ng-postcode` | [`src/`](src), [docs](https://docs.rs/ng-postcode) |
| `ng-postcode` (Python) | The same behaviour, with sync and async clients | `pip install ng-postcode` | [`python/`](python) |
| `ng-postcode-js` | The same behaviour for JavaScript and TypeScript, with a `fetch` client | `npm install ng-postcode-js` | [`js/packages/ng-postcode-js`](js/packages/ng-postcode-js) |
| `ng-postcode` and `ng-postcode-api` (Java) | The same behaviour for Java 17 and later; the core has no dependencies | `io.github.adeniyikayodee:ng-postcode-api` | [`java/`](java) |
| `ng-postcode-mcp` | MCP server: validate, look up, autocomplete, find by location, resolve addresses | `uvx ng-postcode-mcp` | [`mcp/`](mcp) |
| `ng-postcode-mcp` (npm) | The same server for Node, without address resolution | `npx ng-postcode-mcp` | [`js/packages/ng-postcode-mcp`](js/packages/ng-postcode-mcp) |
| `ng-address-resolver` | Resolve free-text addresses to postcodes, only as precisely as the evidence allows (pre-alpha) | `pip install ng-address-resolver` | [`agent/`](agent) |
Each package has its own README with full usage.
## Quick start
**AI assistants**
The MCP server works with any MCP client. It runs over stdio as `uvx ng-postcode-mcp`, with the API key in the environment. Most clients take this entry in their MCP settings:
```json
{
"mcpServers": {
"ng-postcode": {
"command": "uvx",
"args": ["ng-postcode-mcp"],
"env": { "NG_POSTCODE_API_KEY": "nipost_live_..." }
}
}
}
```
To run it with Node, use `"command": "npx"` and `"args": ["-y", "ng-postcode-mcp"]`; that edition has every tool except address resolution. Per-client steps for Cursor, VS Code, Codex, Claude and others are in the [MCP server README](mcp#install). Validation works without a key. The server is listed in the MCP Registry as `io.github.Adeniyikayodee/ng-postcode`.
**Python**
```python
from ng_postcode import Postcode, parse
match parse("ek 01 a03 fk 01"):
case Postcode() as code:
print(code, code.compact) # EK-01-A03-FK-01 EK01A03FK01
case error:
print(error) # e.g. "invalid lga segment"
```
**JavaScript and TypeScript**
```ts
import { Postcode, parse } from "ng-postcode-js";
const code = parse("ek 01 a03 fk 01");
if (code instanceof Postcode) {
console.log(String(code), code.compact); // EK-01-A03-FK-01 EK01A03FK01
} else {
console.log(String(code)); // e.g. "invalid lga segment"
}
```
**Java**
```java
import io.github.adeniyikayodee.ngpostcode.Postcode;
if (Postcode.parse("ek 01 a03 fk 01") instanceof Postcode code) {
System.out.println(code + " " + code.compact()); // EK-01-A03-FK-01 EK01A03FK01
}
```
**Rust**
```rust
use ng_postcode::{Postcode, Segment};
let code: Postcode = "ek 01 a03 fk 01".parse()?;
assert_eq!(code.to_string(), "EK-01-A03-FK-01");
assert_eq!(code.prefix(Segment::Area), "EK-01-A03-FK");
```
## The format
| Segment | Example | Shape |
| --- | --- | --- |
| State | `EK` | 2 letters |
| LGA | `01` | 2 digits, 01 to 99 |
| District | `A03` | 3 letters or digits |
| Area | `FK` | 2 letters |
| Building unit | `01` | 2 digits, 01 to 99 |
Input may be hyphenated, spaced or compact, in either case. The compact form matches `^[A-Z]{2}(0[1-9]|[1-9][0-9])[A-Z0-9]{3}[A-Z]{2}(0[1-9]|[1-9][0-9])$`. A well-formed code is not necessarily assigned to a building; only the NIPOST API can confirm that.
## Passing a postcode between systems
[`docs/schemas/postcode-reference.schema.json`](docs/schemas/postcode-reference.schema.json) defines a small JSON object for handing a location from one system or AI agent to another: the code, its level (`state` to `building`), and optionally a confidence and whether NIPOST confirmed it. A resolved or partial `resolve_address` answer already fits it.
## Design
- **One behaviour, four languages:** Rust, Python, JavaScript and Java all run the cases in [`spec/`](spec), so they cannot drift apart. The Node MCP server registers its tools from [`spec/mcp.json`](spec/mcp.json), which the Python server generates.
- **Offline first:** parsing and validation never touch the network. API access is a separate, optional layer.
- **Errors are values:** expected failures, such as a malformed code or a rejected API key, come back as return values.
- **Careful with money and guesses:** the MCP server caps lookups at the free level unless told otherwise, and never corrects a mistyped code into a paid call. The resolver gives an area or district code when that is all the evidence supports.
## Status
- The NIPOST API needs a key for every endpoint, from the [developer dashboard](https://dashboard.postcode.gov.ng). Offline validation needs nothing.
- The API layer is tested against responses captured from the live API with a level 1 key, kept in [`spec/responses.json`](spec/responses.json). Run [`scripts/live_check.py`](scripts/live_check.py) with your own key to repeat the comparison. Lookup levels 2 and up need a higher-access key and are tested only against NIPOST's documented examples.
- The resolver and the `resolve_address` tool are pre-release. They work against the live API, but their accuracy on real addresses is unmeasured. Described addresses need a geocoder you run or pay for; text alone rarely identifies a building, so ask users for a location pin when the exact building matters.
### Where the live API differs from its docs
Observed on 3 October 2026:
- Every endpoint needs a key, including search, assembly and level 1 lookup, which the docs describe as public.
- Lookup also returns `status` (`valid`, `not_found`, `invalid`) and `verified`. A malformed code is answered with HTTP 200 and `status: invalid`.
- Autocomplete suggestions carry only `code`, the value of the next segment. The documented `label` is not sent.
- Reverse geocoding also returns `depth`.
- Nearby search, which the docs leave unspecified, returns a list of `postcode`, `display` and `distance_m`, nearest first.
- Asking for a level the key lacks returns `403 level_not_granted`.
- An empty autocomplete query never gets a response, so the libraries refuse to send one.
- `EK-01-A03-FK-01`, the example used throughout NIPOST's docs, is reported as not assigned.
## Development
See [CONTRIBUTING.md](CONTRIBUTING.md) for the shared spec, how to add a language, and the commit standards.
```sh
cargo test --all-features # Rust
cd python && uv run --group dev pytest # Python library
cd mcp && uv run --group dev pytest # MCP server
cd agent && uv run --group dev pytest # resolver
cd js && npm ci && npm test # JavaScript library and Node MCP server
cd java && ./mvnw verify # Java libraries
```
CI runs formatting, linting, type checks and tests for every package. Releases publish from tags (`v*` to crates.io; `py-v*`, `mcp-v*` and `agent-v*` to PyPI and the MCP Registry; `js-v*` and `js-mcp-v*` to npm) through trusted publishing, so no tokens are stored. Maven Central has no trusted publishing, so `java-v*` uses a token and a signing key held as environment secrets, and the upload is published by hand.
## License
MIT
What people ask about ng-postcode
What is Adeniyikayodee/ng-postcode?
+
Adeniyikayodee/ng-postcode is mcp servers for the Claude AI ecosystem. Rust, Python, JavaScript, and Java libraries and MCP servers for Nigeria's NIPOST digital postcode (NDAPS): offline validation, lookup, and reverse geocoding. It has 3 GitHub stars and its last recorded update is dated 2026-10-04.
How do I install ng-postcode?
+
You can install ng-postcode by cloning the repository (https://github.com/Adeniyikayodee/ng-postcode) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is Adeniyikayodee/ng-postcode safe to use?
+
Our security agent has analyzed Adeniyikayodee/ng-postcode and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains Adeniyikayodee/ng-postcode?
+
Adeniyikayodee/ng-postcode is maintained by Adeniyikayodee. The last recorded GitHub activity is dated 2026-10-04, with 1 open issues.
Are there alternatives to ng-postcode?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy ng-postcode to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/adeniyikayodee-ng-postcode)<a href="https://claudewave.com/repo/adeniyikayodee-ng-postcode"><img src="https://claudewave.com/api/badge/adeniyikayodee-ng-postcode" alt="Featured on ClaudeWave: Adeniyikayodee/ng-postcode" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
The fastest path to AI-powered full stack observability, even for lean teams.