Nigeria Postcode
Validate, look up and resolve addresses to Nigeria's NIPOST digital postcodes (NDAPS).
Installation
Ajoutez ceci à la configuration MCP de votre client (Claude Desktop : claude_desktop_config.json ; Cursor : .cursor/mcp.json ; VS Code et les autres utilisent la même forme « mcpServers »).
ng-postcode-mcpclaude mcp add nigeria-postcode -e 'NG_POSTCODE_API_KEY=<your ng_postcode_api_key>' -e 'NG_POSTCODE_MAX_LEVEL=1' -e 'NG_POSTCODE_MAX_PAID_CALLS=25' -e 'NG_POSTCODE_BASE_URL=https://api.postcode.gov.ng' -e 'NG_GEOCODER_URL=<NG_GEOCODER_URL>' -e 'NG_GEOCODER_CONTACT=<NG_GEOCODER_CONTACT>' -e 'NG_POSTCODE_TRANSPORT=stdio' -e 'NG_POSTCODE_HOST=127.0.0.1' -e 'NG_POSTCODE_PORT=8000' -e 'NG_POSTCODE_ALLOW_SHARED_KEY=<NG_POSTCODE_ALLOW_SHARED_KEY>' -e 'NG_POSTCODE_ALLOWED_HOSTS=<NG_POSTCODE_ALLOWED_HOSTS>' -- uvx ng-postcode-mcp==0.6.3
{
"mcpServers": {
"nigeria-postcode": {
"command": "uvx",
"args": [
"ng-postcode-mcp==0.6.3"
],
"env": {
"NG_POSTCODE_API_KEY": "<your ng_postcode_api_key>",
"NG_POSTCODE_MAX_LEVEL": "1",
"NG_POSTCODE_MAX_PAID_CALLS": "25",
"NG_POSTCODE_BASE_URL": "https://api.postcode.gov.ng",
"NG_GEOCODER_URL": "<NG_GEOCODER_URL>",
"NG_GEOCODER_CONTACT": "<NG_GEOCODER_CONTACT>",
"NG_POSTCODE_TRANSPORT": "stdio",
"NG_POSTCODE_HOST": "127.0.0.1",
"NG_POSTCODE_PORT": "8000",
"NG_POSTCODE_ALLOW_SHARED_KEY": "<NG_POSTCODE_ALLOW_SHARED_KEY>",
"NG_POSTCODE_ALLOWED_HOSTS": "<NG_POSTCODE_ALLOWED_HOSTS>"
}
}
}
}
Variables d'environnement
NG_POSTCODE_API_KEYsecret NIPOST Postcode API key from dashboard.postcode.gov.ng. Validation works without it.NG_POSTCODE_MAX_LEVELHighest lookup level tools may request. Levels 2 and up consume NIPOST credits.NG_POSTCODE_MAX_PAID_CALLSHow many paid lookups one run of the server may make with its own key.NG_POSTCODE_BASE_URLAlternative API host, such as a staging stack.NG_GEOCODER_URLNominatim server used by resolve_address to place described addresses. Ideally your own instance.NG_GEOCODER_CONTACTURL or email identifying you to the geocoder. Required for the public Nominatim.NG_POSTCODE_TRANSPORTstdio (default), or http to serve streamable HTTP at /mcp on NG_POSTCODE_HOST and NG_POSTCODE_PORT.NG_POSTCODE_HOSTAddress the HTTP transport listens on.NG_POSTCODE_PORTPort the HTTP transport listens on.NG_POSTCODE_ALLOW_SHARED_KEYSet to 1 to let the HTTP transport start with a server key on a public address.NG_POSTCODE_ALLOWED_HOSTSHost names the HTTP transport answers to, separated by commas. Required with a server key on a public address.
ng-postcode-mcpclaude mcp add nigeria-postcode -e 'NG_POSTCODE_API_KEY=<your ng_postcode_api_key>' -e 'NG_POSTCODE_MAX_LEVEL=1' -e 'NG_POSTCODE_MAX_PAID_CALLS=25' -e 'NG_POSTCODE_BASE_URL=https://api.postcode.gov.ng' -- npx -y ng-postcode-mcp@0.4.2
{
"mcpServers": {
"nigeria-postcode": {
"command": "npx",
"args": [
"-y",
"ng-postcode-mcp@0.4.2"
],
"env": {
"NG_POSTCODE_API_KEY": "<your ng_postcode_api_key>",
"NG_POSTCODE_MAX_LEVEL": "1",
"NG_POSTCODE_MAX_PAID_CALLS": "25",
"NG_POSTCODE_BASE_URL": "https://api.postcode.gov.ng"
}
}
}
}
Variables d'environnement
NG_POSTCODE_API_KEYsecret NIPOST Postcode API key from dashboard.postcode.gov.ng. Validation works without it.NG_POSTCODE_MAX_LEVELHighest lookup level tools may request. Levels 2 and up consume NIPOST credits.NG_POSTCODE_MAX_PAID_CALLSHow many paid lookups one run of the server may make with its own key.NG_POSTCODE_BASE_URLAlternative API host, such as a staging stack.
Documentation
Tirée du README du projet sur GitHub, actualisée chaque semaine. Les liens ouvrent GitHub.
Sommaire
ng-postcode
Developer tools for Nigeria's National Digital Alphanumeric Postcode System (NDAPS), the building-level postcode NIPOST launched in October 2026: libraries for Rust and Python (ng-postcode), JavaScript (ng-postcode-js on npm), and Java (ng-postcode-api), 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. NIPOST's own example, FC 02 A09 DB 09, is the same shape with spaces.
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/, docs |
ng-postcode (Python) | The same behaviour, with sync and async clients | pip install ng-postcode | 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 |
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/ |
ng-postcode-mcp | MCP server: validate, look up, autocomplete, find by location, resolve addresses | uvx ng-postcode-mcp | mcp/ |
ng-postcode-mcp (npm) | The same server for Node, without address resolution | npx ng-postcode-mcp | js/packages/ng-postcode-mcp |
ng-postcode-polars | Polars expressions that parse, format and group codes by place, compiled from the Rust core | pip install ng-postcode-polars | native/polars |
ng_postcode (PostgreSQL) | The postcode as native 8-byte types with index support, compiled from the Rust core | Package from Releases, then CREATE EXTENSION ng_postcode | native/pg |
ng_postcode (DuckDB) | The same functions as a DuckDB extension, compiled from the Rust core | INSTALL ng_postcode FROM community (DuckDB 1.5.6) | ng-postcode-duckdb |
ng-address-resolver | Resolve free-text addresses to postcodes, only as precisely as the evidence allows (pre-alpha) | pip install ng-address-resolver | agent/ |
Each package has its own README with full usage.
For databases, sql/ holds the postcode as a PostgreSQL domain and as DuckDB macros, in plain SQL that runs the same shared cases.
Two names are easy to get wrong. On npm the library is ng-postcode-js, because ng-postcode there is another project. ng-address-resolver is imported as ng_address.
For online stores, ng-postcode-woocommerce is a WooCommerce plugin built on the same rules and the same shared test cases: it checks and tidies the postcode at checkout, finds it from the customer's location, and makes shipping zones match on postcode prefixes.
For React and Next.js, templates/nigerian-address-form is a checkout address form built with shadcn/ui and ng-postcode-js. Add it with npx shadcn@latest add https://adeniyikayodee.github.io/ng-postcode/r/nigerian-address-form.json, or deploy the folder as an app.
Quick start
Parsing and validation are offline and need no key.
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
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
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
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");
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:
{
"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. Validation works without a key; the other tools need one from the NIPOST developer dashboard. The server is listed in the MCP Registry as io.github.Adeniyikayodee/ng-postcode.
PostgreSQL
Load the plain SQL file with psql -f sql/postgres.sql. It needs no extension, so it runs on managed services.
CREATE TABLE customers (
id bigint PRIMARY KEY,
postcode ng_postcode -- refuses anything that is not a compact code
);
INSERT INTO customers VALUES (1, ng_postcode_parse('ek 01 a03 fk 01'));
SELECT ng_postcode_format(ng_postcode_truncate(postcode, 'district')) AS district, count(*)
FROM customers
GROUP BY 1;
-- EK-01-A03 | 1
On a server where you can install an extension, the native extension has the same functions and stores a code in 8 bytes. Unpack the package for your PostgreSQL version from Releases, then run CREATE EXTENSION ng_postcode.
DuckDB
Load the same functions with duckdb my.db < sql/duckdb.sql.
SELECT ng_postcode_parse('ek 01 a03 fk 01');
-- EK01A03FK01
The compiled extension, ng-postcode-duckdb, has the same functions: on DuckDB 1.5.6, run INSTALL ng_postcode FROM community, then LOAD ng_postcode.
Polars
import polars as pl
import ng_postcode_polars # pip install ng-postcode-polars
frame = pl.DataFrame({"postcode": ["ek 01 a03 fk 01", "EK-01-A03-ZZ-14", "100001"]})
print(frame.with_columns(code=pl.col("postcode").ng.parse(), ok=pl.col("postcode").ng.is_valid()))
# ek 01 a03 fk 01 EK01A03FK01 true
# EK-01-A03-ZZ-14 EK01A03ZZ14 true
# 100001 null false
A CSV file
pip install ng-postcode
ng-postcode --column postcode customers.csv --out checked.csv
The output keeps every row and adds the compact code, a status of valid, suggested, invalid, or empty, a suggested correction, and the reason for each invalid row.
For coding agents
Language models trained before October 2026 expect a six-digit Nigerian postcode. To point a coding agent at the current format, paste this into your project's AGENTS.md, CLAUDE.md, or editor rules:
Nigerian postcodes: since 1 October 2026 a building's postcode is NIPOST's 11-character
digital postcode (NDAPS), such as EK-01-A03-FK-01, and a six-digit pattern does not match it.
Validate and format it with ng-postcode (pip, cargo), ng-postcode-js (npm), or
io.github.adeniyikayodee:ng-postcode (Maven). On npm, ng-postcode is a different project.
Reference: https://adeniyikayodee.github.io/ng-postcode/llms.txt
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 |
| Form | Example | Use it to |
|---|---|---|
| Canonical | EK-01-A03-FK-01 | Write a code and pass it between systems |
| Spaced | EK 01 A03 FK 01 | Show a code to people |
| Compact | EK01A03FK01 | Store and compare codes |
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 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.
For a whole address, docs/address-record.md wraps the reference in an address record and maps it onto ISO 20022, FHIR, schema.org, vCard, and UPU's address layout for Nigeria.
Design
- One behaviour, four languages: Rust, Python, JavaScript and Java all run the cases in
spec/, so they cannot drift apart. The Node MCP server registers its tools fromspec/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. 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. Runscripts/live_check.pywith 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_addresstool 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. - Notes for integrators on how the live API behaves, each with the date it was observed, are in
docs/api-differences.md.
Development
See CONTRIBUTING.md for the shared spec, how to add a language, and the commit standards.
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. An mcp-v* release also creates a GitHub release, which Glama rebuilds its listing from, and republishes the Smithery bundle with a key held the same way.
License
MIT
Questions fréquentes
Qu'est-ce que Nigeria Postcode ?
Validate, look up and resolve addresses to Nigeria's NIPOST digital postcodes (NDAPS).
Comment installer Nigeria Postcode ?
Il s'exécute sur votre machine. Dans Claude Code : claude mcp add nigeria-postcode -e 'NG_POSTCODE_API_KEY=<your ng_postcode_api_key>' -e 'NG_POSTCODE_MAX_LEVEL=1' -e 'NG_POSTCODE_MAX_PAID_CALLS=25' -e 'NG_POSTCODE_BASE_URL=https://api.postcode.gov.ng' -e 'NG_GEOCODER_URL=<NG_GEOCODER_URL>' -e 'NG_GEOCODER_CONTACT=<NG_GEOCODER_CONTACT>' -e 'NG_POSTCODE_TRANSPORT=stdio' -e 'NG_POSTCODE_HOST=127.0.0.1' -e 'NG_POSTCODE_PORT=8000' -e 'NG_POSTCODE_ALLOW_SHARED_KEY=<NG_POSTCODE_ALLOW_SHARED_KEY>' -e 'NG_POSTCODE_ALLOWED_HOSTS=<NG_POSTCODE_ALLOWED_HOSTS>' -- uvx ng-postcode-mcp==0.6.3. Pour les autres clients, collez la configuration JSON de cette page dans leurs réglages MCP.
Faut-il une clé API pour Nigeria Postcode ?
Oui. Il attend NG_POSTCODE_API_KEY, à renseigner dans sa configuration.
Nigeria Postcode est-il open source ?
Oui. Son code est sur GitHub sous licence MIT.
Qui maintient Nigeria Postcode ?
Il est publié par Adeniyikayodee. AI.tn le référence sans le maintenir ni le recommander.
Issu du registre MCP officiel. Être listé n'est pas une recommandation : vérifiez le code et les permissions d'un serveur avant de lui donner accès à vos données.