@braynexservices/nigeria-mcp-core 0.1.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/LICENSE +21 -0
- package/NOTICE +38 -0
- package/README.md +24 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/http.d.ts +1 -0
- package/dist/http.js +44 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cache.d.ts +19 -0
- package/dist/lib/cache.js +27 -0
- package/dist/lib/cache.js.map +1 -0
- package/dist/lib/errors.d.ts +13 -0
- package/dist/lib/errors.js +27 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/fetch.d.ts +16 -0
- package/dist/lib/fetch.js +39 -0
- package/dist/lib/fetch.js.map +1 -0
- package/dist/lib/normalize.d.ts +10 -0
- package/dist/lib/normalize.js +12 -0
- package/dist/lib/normalize.js.map +1 -0
- package/dist/providers/registry.d.ts +7 -0
- package/dist/providers/registry.js +9 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +61 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.js +14 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schemas.d.ts +380 -0
- package/dist/schemas.js +122 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +29 -0
- package/dist/server.js +50 -0
- package/dist/server.js.map +1 -0
- package/dist/stdio.d.ts +1 -0
- package/dist/stdio.js +8 -0
- package/dist/stdio.js.map +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Braynex Services Ltd (Samuel Orie)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Nigeria MCP — NOTICE (Copyright, Authorship & Ownership)
|
|
2
|
+
========================================================
|
|
3
|
+
|
|
4
|
+
Copyright © 2026 Braynex Services Ltd. All rights reserved.
|
|
5
|
+
|
|
6
|
+
Author & Founder: Samuel Orie
|
|
7
|
+
Company / Owner: Braynex Services Ltd (https://www.braynexservices.com)
|
|
8
|
+
Contact: braynexservices@gmail.com
|
|
9
|
+
|
|
10
|
+
This repository and the MCP servers, tools, schemas, and supporting code within it
|
|
11
|
+
(collectively, "the Software") are original works authored by Samuel Orie and owned by
|
|
12
|
+
Braynex Services Ltd as company assets. They were independently conceived and built by the
|
|
13
|
+
author; they are not copied from, and are not knowingly derived from, any third party's
|
|
14
|
+
proprietary source code.
|
|
15
|
+
|
|
16
|
+
Third-party data sources accessed at runtime (e.g. UN Comtrade, open.er-api.com) remain
|
|
17
|
+
the property of their respective providers and are used under their own public terms; this
|
|
18
|
+
notice covers only Braynex Services Ltd' own original code in this repository.
|
|
19
|
+
|
|
20
|
+
LICENSING
|
|
21
|
+
---------
|
|
22
|
+
This software is released under the **MIT License** (see the LICENSE file at the repository
|
|
23
|
+
root; each package also declares `"license": "MIT"`). Chosen deliberately for broad adoption.
|
|
24
|
+
|
|
25
|
+
Braynex Services Ltd **retains the copyright** to all original code herein — MIT grants others a
|
|
26
|
+
license to use/modify/redistribute it (with attribution and this notice preserved), but does
|
|
27
|
+
NOT transfer ownership or trademark rights. The "Braynex Services Ltd" brand and product names
|
|
28
|
+
are not licensed for others' use under MIT.
|
|
29
|
+
|
|
30
|
+
TRADEMARKS
|
|
31
|
+
----------
|
|
32
|
+
"Braynex Services Ltd" and the product names used herein (including
|
|
33
|
+
"Nigeria Trade Intel MCP") are unregistered trademarks / brands of Braynex Services Ltd.
|
|
34
|
+
|
|
35
|
+
PROVENANCE
|
|
36
|
+
----------
|
|
37
|
+
Authorship and creation dates are evidenced by this repository's git history. This file
|
|
38
|
+
records ownership; it is not a substitute for formal IP registration or legal advice.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `shared/` — `@braynexservices/nigeria-mcp-core`
|
|
2
|
+
|
|
3
|
+
The shared MCP core consumed by every lane. **No lane logic lives here** — only the reusable spine.
|
|
4
|
+
|
|
5
|
+
## Will contain (built in v1)
|
|
6
|
+
```
|
|
7
|
+
shared/src/
|
|
8
|
+
├── server.ts # buildServer(): new McpServer(), accepts tool registrations
|
|
9
|
+
├── stdio.ts # StdioServerTransport entrypoint (local, no auth)
|
|
10
|
+
├── http.ts # Express + stateless StreamableHTTPServerTransport + API-key auth + /health
|
|
11
|
+
├── config.ts # env parsing, provider selection, key list
|
|
12
|
+
├── schemas.ts # shared Zod base types + Normalized* contracts
|
|
13
|
+
├── providers/types.ts # CacProvider / BankProvider / FxProvider interfaces (the seam)
|
|
14
|
+
└── lib/
|
|
15
|
+
├── normalize.ts # raw → normalized helpers
|
|
16
|
+
├── errors.ts # actionable MCP error helpers
|
|
17
|
+
└── cache.ts # in-memory TTL cache (Redis-swappable)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Design rules
|
|
21
|
+
- The **provider seam** (typed interfaces) is the moat — tools depend on interfaces, never concrete providers. See `brain/04-rules/engineering-rules.md`.
|
|
22
|
+
- Normalized schema stability > provider breadth.
|
|
23
|
+
|
|
24
|
+
> 🧠 Source of truth: `brain/05-plans/v1-plan.md` and `brain/08-tech-stack/core-stack.md`.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment configuration for the Nigeria MCP core.
|
|
3
|
+
* No hardcoded secrets — everything comes from process.env. See brain/04-rules/engineering-rules.md
|
|
4
|
+
*/
|
|
5
|
+
export interface Config {
|
|
6
|
+
cacProvider: string;
|
|
7
|
+
bankProvider: string;
|
|
8
|
+
fxProvider: string;
|
|
9
|
+
driversProvider: string;
|
|
10
|
+
electricityProvider: string;
|
|
11
|
+
credentialProvider: string;
|
|
12
|
+
tradeProvider: string;
|
|
13
|
+
apiKeys: string[];
|
|
14
|
+
port: number;
|
|
15
|
+
cacheTtlSeconds: number;
|
|
16
|
+
paystackSecretKey?: string;
|
|
17
|
+
vtpassApiKey?: string;
|
|
18
|
+
vtpassPublicKey?: string;
|
|
19
|
+
vtpassSecretKey?: string;
|
|
20
|
+
vtpassBaseUrl: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): Config;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment configuration for the Nigeria MCP core.
|
|
3
|
+
* No hardcoded secrets — everything comes from process.env. See brain/04-rules/engineering-rules.md
|
|
4
|
+
*/
|
|
5
|
+
function num(value, fallback) {
|
|
6
|
+
const n = Number(value);
|
|
7
|
+
return Number.isFinite(n) ? n : fallback;
|
|
8
|
+
}
|
|
9
|
+
export function loadConfig(env = process.env) {
|
|
10
|
+
return {
|
|
11
|
+
cacProvider: env.CAC_PROVIDER ?? "mock",
|
|
12
|
+
bankProvider: env.BANK_PROVIDER ?? "mock",
|
|
13
|
+
fxProvider: env.FX_PROVIDER ?? "mock",
|
|
14
|
+
driversProvider: env.DRIVERS_PROVIDER ?? "mock",
|
|
15
|
+
electricityProvider: env.ELECTRICITY_PROVIDER ?? "mock",
|
|
16
|
+
credentialProvider: env.CREDENTIAL_PROVIDER ?? "mock",
|
|
17
|
+
tradeProvider: env.TRADE_PROVIDER ?? "mock",
|
|
18
|
+
apiKeys: (env.API_KEYS ?? "")
|
|
19
|
+
.split(",")
|
|
20
|
+
.map((s) => s.trim())
|
|
21
|
+
.filter(Boolean),
|
|
22
|
+
port: num(env.PORT, 8787),
|
|
23
|
+
cacheTtlSeconds: num(env.CACHE_TTL_SECONDS, 300),
|
|
24
|
+
paystackSecretKey: env.PAYSTACK_SECRET_KEY,
|
|
25
|
+
vtpassApiKey: env.VTPASS_API_KEY,
|
|
26
|
+
vtpassPublicKey: env.VTPASS_PUBLIC_KEY,
|
|
27
|
+
vtpassSecretKey: env.VTPASS_SECRET_KEY,
|
|
28
|
+
// sandbox by default; set VTPASS_BASE_URL=https://vtpass.com/api + live keys for production
|
|
29
|
+
vtpassBaseUrl: env.VTPASS_BASE_URL ?? "https://sandbox.vtpass.com/api",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH,SAAS,GAAG,CAAC,KAAyB,EAAE,QAAgB;IACtD,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,OAAO;QACL,WAAW,EAAE,GAAG,CAAC,YAAY,IAAI,MAAM;QACvC,YAAY,EAAE,GAAG,CAAC,aAAa,IAAI,MAAM;QACzC,UAAU,EAAE,GAAG,CAAC,WAAW,IAAI,MAAM;QACrC,eAAe,EAAE,GAAG,CAAC,gBAAgB,IAAI,MAAM;QAC/C,mBAAmB,EAAE,GAAG,CAAC,oBAAoB,IAAI,MAAM;QACvD,kBAAkB,EAAE,GAAG,CAAC,mBAAmB,IAAI,MAAM;QACrD,aAAa,EAAE,GAAG,CAAC,cAAc,IAAI,MAAM;QAC3C,OAAO,EAAE,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;aAC1B,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;QAClB,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC;QACzB,eAAe,EAAE,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,GAAG,CAAC;QAChD,iBAAiB,EAAE,GAAG,CAAC,mBAAmB;QAC1C,YAAY,EAAE,GAAG,CAAC,cAAc;QAChC,eAAe,EAAE,GAAG,CAAC,iBAAiB;QACtC,eAAe,EAAE,GAAG,CAAC,iBAAiB;QACtC,4FAA4F;QAC5F,aAAa,EAAE,GAAG,CAAC,eAAe,IAAI,gCAAgC;KACvE,CAAC;AACJ,CAAC"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamable-HTTP entrypoint — stateless, deployable. API-key auth + /health.
|
|
3
|
+
* Stateless mode (sessionIdGenerator: undefined) is simpler to scale. A fresh server +
|
|
4
|
+
* transport is created per request. See brain/08-tech-stack/core-stack.md
|
|
5
|
+
*/
|
|
6
|
+
import express from "express";
|
|
7
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
8
|
+
import { loadConfig } from "./config.js";
|
|
9
|
+
import { buildServer, pingTool } from "./server.js";
|
|
10
|
+
const config = loadConfig();
|
|
11
|
+
const app = express();
|
|
12
|
+
app.use(express.json());
|
|
13
|
+
app.get("/health", (_req, res) => {
|
|
14
|
+
res.json({ status: "ok", service: "nigeria-mcp" });
|
|
15
|
+
});
|
|
16
|
+
function authorized(req) {
|
|
17
|
+
// No keys configured => open (local dev). Configure API_KEYS to enforce.
|
|
18
|
+
if (config.apiKeys.length === 0)
|
|
19
|
+
return true;
|
|
20
|
+
const fromHeader = req.header("x-api-key");
|
|
21
|
+
const bearer = req.header("authorization")?.replace(/^Bearer\s+/i, "");
|
|
22
|
+
const key = fromHeader ?? bearer;
|
|
23
|
+
return !!key && config.apiKeys.includes(key);
|
|
24
|
+
}
|
|
25
|
+
app.post("/mcp", async (req, res) => {
|
|
26
|
+
if (!authorized(req)) {
|
|
27
|
+
res
|
|
28
|
+
.status(401)
|
|
29
|
+
.json({ jsonrpc: "2.0", error: { code: -32001, message: "Unauthorized" }, id: null });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const server = buildServer([pingTool]);
|
|
33
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
34
|
+
res.on("close", () => {
|
|
35
|
+
void transport.close();
|
|
36
|
+
void server.close();
|
|
37
|
+
});
|
|
38
|
+
await server.connect(transport);
|
|
39
|
+
await transport.handleRequest(req, res, req.body);
|
|
40
|
+
});
|
|
41
|
+
app.listen(config.port, () => {
|
|
42
|
+
console.error(`[nigeria-mcp] HTTP listening on :${config.port} (auth: ${config.apiKeys.length ? "on" : "off"})`);
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,OAAwC,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAExB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IAClD,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,SAAS,UAAU,CAAC,GAAY;IAC9B,yEAAyE;IACzE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,UAAU,IAAI,MAAM,CAAC;IACjC,OAAO,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACrD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,GAAG;aACA,MAAM,CAAC,GAAG,CAAC;aACX,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACxF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC,CAAC;IACvF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACnB,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IAC3B,OAAO,CAAC,KAAK,CACX,oCAAoC,MAAM,CAAC,IAAI,WAAW,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAClG,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @braynexservices/nigeria-mcp-core — public surface consumed by every lane.
|
|
3
|
+
*/
|
|
4
|
+
export * from "./config.js";
|
|
5
|
+
export * from "./schemas.js";
|
|
6
|
+
export * from "./providers/types.js";
|
|
7
|
+
export * from "./providers/registry.js";
|
|
8
|
+
export * from "./lib/cache.js";
|
|
9
|
+
export * from "./lib/errors.js";
|
|
10
|
+
export * from "./lib/fetch.js";
|
|
11
|
+
export * from "./lib/normalize.js";
|
|
12
|
+
export * from "./server.js";
|
|
13
|
+
export * from "./runtime.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @braynexservices/nigeria-mcp-core — public surface consumed by every lane.
|
|
3
|
+
*/
|
|
4
|
+
export * from "./config.js";
|
|
5
|
+
export * from "./schemas.js";
|
|
6
|
+
export * from "./providers/types.js";
|
|
7
|
+
export * from "./providers/registry.js";
|
|
8
|
+
export * from "./lib/cache.js";
|
|
9
|
+
export * from "./lib/errors.js";
|
|
10
|
+
export * from "./lib/fetch.js";
|
|
11
|
+
export * from "./lib/normalize.js";
|
|
12
|
+
export * from "./server.js";
|
|
13
|
+
export * from "./runtime.js";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory TTL cache. Same get/set surface a Redis-backed cache will implement later,
|
|
3
|
+
* so lanes can stay cache-agnostic. See brain/08-tech-stack/core-stack.md
|
|
4
|
+
*/
|
|
5
|
+
export interface Cache {
|
|
6
|
+
get<T>(key: string): T | undefined;
|
|
7
|
+
set<T>(key: string, value: T, ttlSeconds?: number): void;
|
|
8
|
+
delete(key: string): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare class MemoryCache implements Cache {
|
|
12
|
+
private readonly defaultTtlSeconds;
|
|
13
|
+
private readonly store;
|
|
14
|
+
constructor(defaultTtlSeconds: number);
|
|
15
|
+
get<T>(key: string): T | undefined;
|
|
16
|
+
set<T>(key: string, value: T, ttlSeconds?: number): void;
|
|
17
|
+
delete(key: string): void;
|
|
18
|
+
clear(): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class MemoryCache {
|
|
2
|
+
defaultTtlSeconds;
|
|
3
|
+
store = new Map();
|
|
4
|
+
constructor(defaultTtlSeconds) {
|
|
5
|
+
this.defaultTtlSeconds = defaultTtlSeconds;
|
|
6
|
+
}
|
|
7
|
+
get(key) {
|
|
8
|
+
const entry = this.store.get(key);
|
|
9
|
+
if (!entry)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (entry.expiresAt <= Date.now()) {
|
|
12
|
+
this.store.delete(key);
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return entry.value;
|
|
16
|
+
}
|
|
17
|
+
set(key, value, ttlSeconds = this.defaultTtlSeconds) {
|
|
18
|
+
this.store.set(key, { value, expiresAt: Date.now() + ttlSeconds * 1000 });
|
|
19
|
+
}
|
|
20
|
+
delete(key) {
|
|
21
|
+
this.store.delete(key);
|
|
22
|
+
}
|
|
23
|
+
clear() {
|
|
24
|
+
this.store.clear();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/lib/cache.ts"],"names":[],"mappings":"AAgBA,MAAM,OAAO,WAAW;IAGO;IAFZ,KAAK,GAAG,IAAI,GAAG,EAAiB,CAAC;IAElD,YAA6B,iBAAyB;QAAzB,sBAAiB,GAAjB,iBAAiB,CAAQ;IAAG,CAAC;IAE1D,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,KAAU,CAAC;IAC1B,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,KAAQ,EAAE,aAAqB,IAAI,CAAC,iBAAiB;QACvE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actionable errors. Tool handlers throw ToolError with a hint; buildServer converts any
|
|
3
|
+
* throw into a clean, agent-readable tool result. See brain/04-rules/engineering-rules.md
|
|
4
|
+
*/
|
|
5
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
export declare class ToolError extends Error {
|
|
7
|
+
readonly hint?: string | undefined;
|
|
8
|
+
constructor(message: string, hint?: string | undefined);
|
|
9
|
+
}
|
|
10
|
+
/** Throw a not-found error with an optional next-step hint for the agent. */
|
|
11
|
+
export declare function notFound(what: string, hint?: string): never;
|
|
12
|
+
/** Convert any error into a CallToolResult with isError + a helpful message. */
|
|
13
|
+
export declare function toToolResult(err: unknown): CallToolResult;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class ToolError extends Error {
|
|
2
|
+
hint;
|
|
3
|
+
constructor(message, hint) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.hint = hint;
|
|
6
|
+
this.name = "ToolError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** Throw a not-found error with an optional next-step hint for the agent. */
|
|
10
|
+
export function notFound(what, hint) {
|
|
11
|
+
throw new ToolError(`${what} not found.`, hint);
|
|
12
|
+
}
|
|
13
|
+
/** Convert any error into a CallToolResult with isError + a helpful message. */
|
|
14
|
+
export function toToolResult(err) {
|
|
15
|
+
const message = err instanceof ToolError
|
|
16
|
+
? err.hint
|
|
17
|
+
? `${err.message} ${err.hint}`
|
|
18
|
+
: err.message
|
|
19
|
+
: err instanceof Error
|
|
20
|
+
? err.message
|
|
21
|
+
: String(err);
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
24
|
+
isError: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGhB;IAFlB,YACE,OAAe,EACC,IAAa;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,SAAI,GAAJ,IAAI,CAAS;QAG7B,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAa;IAClD,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,aAAa,EAAE,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,OAAO,GACX,GAAG,YAAY,SAAS;QACtB,CAAC,CAAC,GAAG,CAAC,IAAI;YACR,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE;YAC9B,CAAC,CAAC,GAAG,CAAC,OAAO;QACf,CAAC,CAAC,GAAG,YAAY,KAAK;YACpB,CAAC,CAAC,GAAG,CAAC,OAAO;YACb,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;QACtD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface FetchJsonOptions {
|
|
2
|
+
/** Human label for error messages, e.g. "Paystack". */
|
|
3
|
+
service: string;
|
|
4
|
+
/** Actionable tail appended to transient hints, e.g. "set BANK_PROVIDER=mock". */
|
|
5
|
+
fallbackHint: string;
|
|
6
|
+
/** Per-attempt timeout in ms. Default 15s. */
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
/** Backoff (ms) before each attempt; first entry is usually 0. Default [0, 600, 1500]. */
|
|
9
|
+
backoffsMs?: number[];
|
|
10
|
+
}
|
|
11
|
+
export interface FetchJsonResult {
|
|
12
|
+
res: Response;
|
|
13
|
+
/** Parsed JSON body, or null if the response was not valid JSON. */
|
|
14
|
+
body: unknown;
|
|
15
|
+
}
|
|
16
|
+
export declare function fetchJson(url: string, init: RequestInit, opts: FetchJsonOptions): Promise<FetchJsonResult>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared fetch-with-retry used by every live adapter. Applies a per-attempt timeout and
|
|
3
|
+
* backoff-retry on TRANSIENT failures — network/timeout rejections, HTTP 429, and 5xx.
|
|
4
|
+
* (Hand-rolled retry loops in each adapter used to let a fetch() rejection escape unretried;
|
|
5
|
+
* centralizing it fixes that once.)
|
|
6
|
+
*
|
|
7
|
+
* Non-retryable responses are returned to the caller as { res, body } so each adapter keeps
|
|
8
|
+
* its own status/body policy — e.g. treat 401/403 as an auth error, or trust a provider's
|
|
9
|
+
* JSON envelope on a benign 4xx. Throws a ToolError only when all attempts are exhausted.
|
|
10
|
+
*/
|
|
11
|
+
import { ToolError } from "./errors.js";
|
|
12
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
13
|
+
export async function fetchJson(url, init, opts) {
|
|
14
|
+
const timeoutMs = opts.timeoutMs ?? 15_000;
|
|
15
|
+
const backoffs = opts.backoffsMs ?? [0, 600, 1500];
|
|
16
|
+
let lastError = null;
|
|
17
|
+
for (const backoff of backoffs) {
|
|
18
|
+
if (backoff)
|
|
19
|
+
await sleep(backoff);
|
|
20
|
+
let res;
|
|
21
|
+
try {
|
|
22
|
+
res = await fetch(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// Timeout / DNS / connection reset — a transient we should retry, not leak raw.
|
|
26
|
+
lastError = new ToolError(`${opts.service} did not respond (network error or timeout).`, `Retried; try again shortly, or ${opts.fallbackHint}.`);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (res.status === 429 || res.status >= 500) {
|
|
30
|
+
lastError = new ToolError(`${opts.service} is rate-limited or unavailable (HTTP ${res.status}).`, `Retried; try again shortly, or ${opts.fallbackHint}.`);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const body = await res.json().catch(() => null);
|
|
34
|
+
return { res, body };
|
|
35
|
+
}
|
|
36
|
+
throw (lastError ??
|
|
37
|
+
new ToolError(`${opts.service} request failed after retries.`, `Try again shortly, or ${opts.fallbackHint}.`));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/lib/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmBxC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAEnF,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,IAAiB,EACjB,IAAsB;IAEtB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAEnD,IAAI,SAAS,GAAqB,IAAI,CAAC;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO;YAAE,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;QAAC,MAAM,CAAC;YACP,gFAAgF;YAChF,SAAS,GAAG,IAAI,SAAS,CACvB,GAAG,IAAI,CAAC,OAAO,8CAA8C,EAC7D,kCAAkC,IAAI,CAAC,YAAY,GAAG,CACvD,CAAC;YACF,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC5C,SAAS,GAAG,IAAI,SAAS,CACvB,GAAG,IAAI,CAAC,OAAO,yCAAyC,GAAG,CAAC,MAAM,IAAI,EACtE,kCAAkC,IAAI,CAAC,YAAY,GAAG,CACvD,CAAC;YACF,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC;IACD,MAAM,CACJ,SAAS;QACT,IAAI,SAAS,CACX,GAAG,IAAI,CAAC,OAAO,gCAAgC,EAC/C,yBAAyB,IAAI,CAAC,YAAY,GAAG,CAC9C,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalization helpers. Lane adapters map raw provider payloads into the schemas in
|
|
3
|
+
* schemas.ts and stamp provenance via these helpers.
|
|
4
|
+
*/
|
|
5
|
+
export declare function nowIso(): string;
|
|
6
|
+
/** Stamp source + retrievedAt onto a normalized record. */
|
|
7
|
+
export declare function stamp<T extends object>(record: T, source: string): T & {
|
|
8
|
+
source: string;
|
|
9
|
+
retrievedAt: string;
|
|
10
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalization helpers. Lane adapters map raw provider payloads into the schemas in
|
|
3
|
+
* schemas.ts and stamp provenance via these helpers.
|
|
4
|
+
*/
|
|
5
|
+
export function nowIso() {
|
|
6
|
+
return new Date().toISOString();
|
|
7
|
+
}
|
|
8
|
+
/** Stamp source + retrievedAt onto a normalized record. */
|
|
9
|
+
export function stamp(record, source) {
|
|
10
|
+
return { ...record, source, retrievedAt: nowIso() };
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/lib/normalize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,MAAM;IACpB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,KAAK,CACnB,MAAS,EACT,MAAc;IAEd,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic provider factory. Each lane builds a registry of { key -> factory } and calls
|
|
3
|
+
* selectProvider() with the env-selected key. Keeps provider selection uniform + typed.
|
|
4
|
+
*/
|
|
5
|
+
export type ProviderFactory<T> = () => T;
|
|
6
|
+
export type ProviderRegistry<T> = Record<string, ProviderFactory<T>>;
|
|
7
|
+
export declare function selectProvider<T>(kind: string, key: string, registry: ProviderRegistry<T>): T;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function selectProvider(kind, key, registry) {
|
|
2
|
+
const factory = registry[key];
|
|
3
|
+
if (!factory) {
|
|
4
|
+
const available = Object.keys(registry).join(", ") || "(none)";
|
|
5
|
+
throw new Error(`Unknown ${kind} provider "${key}". Available: ${available}. Set the provider env var accordingly.`);
|
|
6
|
+
}
|
|
7
|
+
return factory();
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,GAAW,EACX,QAA6B;IAE7B,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;QAC/D,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,cAAc,GAAG,iBAAiB,SAAS,yCAAyC,CACpG,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider seam — the moat. Tools depend on these interfaces, never on a concrete
|
|
3
|
+
* provider. Selecting/swapping a provider is one env var; adding one is one new file.
|
|
4
|
+
* See brain/02-strategy/positioning.md
|
|
5
|
+
*/
|
|
6
|
+
import type { NormalizedCompany, CompanyProfile, SearchHit, NormalizedBankAccount, FxRate, NormalizedDriversLicense, NormalizedVehicle, NormalizedMeter, NormalizedCredential, NormalizedTradeFlow, NormalizedHsCode } from "../schemas.js";
|
|
7
|
+
export interface BankRef {
|
|
8
|
+
name: string;
|
|
9
|
+
code: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CacProvider {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
verify(rcOrName: string): Promise<NormalizedCompany>;
|
|
14
|
+
search(query: string): Promise<SearchHit[]>;
|
|
15
|
+
profile(rc: string): Promise<CompanyProfile>;
|
|
16
|
+
}
|
|
17
|
+
export interface BankProvider {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
resolve(accountNumber: string, bankCode: string): Promise<NormalizedBankAccount>;
|
|
20
|
+
listBanks(): Promise<BankRef[]>;
|
|
21
|
+
}
|
|
22
|
+
export interface FxProvider {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
rates(base?: string, quote?: string): Promise<FxRate[]>;
|
|
25
|
+
}
|
|
26
|
+
export interface DriversProvider {
|
|
27
|
+
readonly name: string;
|
|
28
|
+
verifyLicense(licenseNumber: string, dob?: string): Promise<NormalizedDriversLicense>;
|
|
29
|
+
verifyPlate(plateNumber: string): Promise<NormalizedVehicle>;
|
|
30
|
+
}
|
|
31
|
+
export interface Disco {
|
|
32
|
+
code: string;
|
|
33
|
+
name: string;
|
|
34
|
+
}
|
|
35
|
+
/** Electricity meter provider. READ-ONLY by design — no pay/recharge methods (NERC/CBN/AML). */
|
|
36
|
+
export interface MeterProvider {
|
|
37
|
+
readonly name: string;
|
|
38
|
+
validate(meterNumber: string, disco: string, meterType: string): Promise<NormalizedMeter>;
|
|
39
|
+
listDiscos(): Promise<Disco[]>;
|
|
40
|
+
}
|
|
41
|
+
/** Credential (KYE) provider. Wrap licensed aggregators (NDPR) — never scrape WAEC/JAMB. */
|
|
42
|
+
export interface CredentialProvider {
|
|
43
|
+
readonly name: string;
|
|
44
|
+
verify(type: string, candidateName: string, identifier: string): Promise<NormalizedCredential>;
|
|
45
|
+
verifyTeacher(trcnNumber: string): Promise<NormalizedCredential>;
|
|
46
|
+
}
|
|
47
|
+
/** Query for trade statistics. `commodity` is an HS code OR an aggregation level keyword. */
|
|
48
|
+
export interface TradeStatsQuery {
|
|
49
|
+
flow: string;
|
|
50
|
+
partner?: string;
|
|
51
|
+
commodity?: string;
|
|
52
|
+
year?: number;
|
|
53
|
+
frequency?: string;
|
|
54
|
+
month?: number;
|
|
55
|
+
}
|
|
56
|
+
/** Trade-intelligence provider. Wrap OPEN global APIs (UN Comtrade, WITS) — not NICIS II. */
|
|
57
|
+
export interface TradeProvider {
|
|
58
|
+
readonly name: string;
|
|
59
|
+
tradeStats(query: TradeStatsQuery): Promise<NormalizedTradeFlow[]>;
|
|
60
|
+
classifyHs(productDescription: string): Promise<NormalizedHsCode>;
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport runners. Lanes call startStdio() with their tools so they never import the
|
|
3
|
+
* MCP SDK transport directly — all SDK wiring stays in core.
|
|
4
|
+
*/
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { buildServer } from "./server.js";
|
|
7
|
+
/** Build a server from the given tools and serve it over stdio (local use). */
|
|
8
|
+
export async function startStdio(tools, opts = {}) {
|
|
9
|
+
const server = buildServer(tools, opts);
|
|
10
|
+
const transport = new StdioServerTransport();
|
|
11
|
+
await server.connect(transport);
|
|
12
|
+
console.error(`[${opts.name ?? "nigeria-mcp"}] stdio connected (${tools.length} tools)`);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAyC,MAAM,aAAa,CAAC;AAEjF,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAgB,EAAE,OAA2B,EAAE;IAC9E,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,aAAa,sBAAsB,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized, agent-facing data contracts. The SAME shape is returned regardless of
|
|
3
|
+
* which upstream provider served the request — this stability is the product.
|
|
4
|
+
* See brain/04-rules/engineering-rules.md and the lane dossiers in brain/07-lanes/.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
/** Provenance fields stamped onto every normalized record. */
|
|
8
|
+
export declare const Provenance: {
|
|
9
|
+
source: z.ZodString;
|
|
10
|
+
retrievedAt: z.ZodString;
|
|
11
|
+
};
|
|
12
|
+
export declare const NormalizedCompany: z.ZodObject<{
|
|
13
|
+
source: z.ZodString;
|
|
14
|
+
retrievedAt: z.ZodString;
|
|
15
|
+
rcNumber: z.ZodString;
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
status: z.ZodString;
|
|
18
|
+
address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
19
|
+
registrationDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
|
+
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
name: string;
|
|
23
|
+
status: string;
|
|
24
|
+
rcNumber: string;
|
|
25
|
+
source: string;
|
|
26
|
+
retrievedAt: string;
|
|
27
|
+
type?: string | null | undefined;
|
|
28
|
+
address?: string | null | undefined;
|
|
29
|
+
registrationDate?: string | null | undefined;
|
|
30
|
+
}, {
|
|
31
|
+
name: string;
|
|
32
|
+
status: string;
|
|
33
|
+
rcNumber: string;
|
|
34
|
+
source: string;
|
|
35
|
+
retrievedAt: string;
|
|
36
|
+
type?: string | null | undefined;
|
|
37
|
+
address?: string | null | undefined;
|
|
38
|
+
registrationDate?: string | null | undefined;
|
|
39
|
+
}>;
|
|
40
|
+
export type NormalizedCompany = z.infer<typeof NormalizedCompany>;
|
|
41
|
+
export declare const Director: z.ZodObject<{
|
|
42
|
+
name: z.ZodString;
|
|
43
|
+
role: z.ZodOptional<z.ZodString>;
|
|
44
|
+
}, "strip", z.ZodTypeAny, {
|
|
45
|
+
name: string;
|
|
46
|
+
role?: string | undefined;
|
|
47
|
+
}, {
|
|
48
|
+
name: string;
|
|
49
|
+
role?: string | undefined;
|
|
50
|
+
}>;
|
|
51
|
+
export type Director = z.infer<typeof Director>;
|
|
52
|
+
export declare const Shareholder: z.ZodObject<{
|
|
53
|
+
name: z.ZodString;
|
|
54
|
+
shares: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
name: string;
|
|
57
|
+
shares?: number | undefined;
|
|
58
|
+
}, {
|
|
59
|
+
name: string;
|
|
60
|
+
shares?: number | undefined;
|
|
61
|
+
}>;
|
|
62
|
+
export type Shareholder = z.infer<typeof Shareholder>;
|
|
63
|
+
export declare const CompanyProfile: z.ZodObject<{
|
|
64
|
+
source: z.ZodString;
|
|
65
|
+
retrievedAt: z.ZodString;
|
|
66
|
+
rcNumber: z.ZodString;
|
|
67
|
+
name: z.ZodString;
|
|
68
|
+
status: z.ZodString;
|
|
69
|
+
address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
70
|
+
registrationDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
71
|
+
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
72
|
+
} & {
|
|
73
|
+
classification: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
74
|
+
email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
75
|
+
directors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
76
|
+
name: z.ZodString;
|
|
77
|
+
role: z.ZodOptional<z.ZodString>;
|
|
78
|
+
}, "strip", z.ZodTypeAny, {
|
|
79
|
+
name: string;
|
|
80
|
+
role?: string | undefined;
|
|
81
|
+
}, {
|
|
82
|
+
name: string;
|
|
83
|
+
role?: string | undefined;
|
|
84
|
+
}>, "many">>;
|
|
85
|
+
shareholders: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
86
|
+
name: z.ZodString;
|
|
87
|
+
shares: z.ZodOptional<z.ZodNumber>;
|
|
88
|
+
}, "strip", z.ZodTypeAny, {
|
|
89
|
+
name: string;
|
|
90
|
+
shares?: number | undefined;
|
|
91
|
+
}, {
|
|
92
|
+
name: string;
|
|
93
|
+
shares?: number | undefined;
|
|
94
|
+
}>, "many">>;
|
|
95
|
+
}, "strip", z.ZodTypeAny, {
|
|
96
|
+
name: string;
|
|
97
|
+
status: string;
|
|
98
|
+
rcNumber: string;
|
|
99
|
+
source: string;
|
|
100
|
+
retrievedAt: string;
|
|
101
|
+
email?: string | null | undefined;
|
|
102
|
+
type?: string | null | undefined;
|
|
103
|
+
address?: string | null | undefined;
|
|
104
|
+
registrationDate?: string | null | undefined;
|
|
105
|
+
classification?: string | null | undefined;
|
|
106
|
+
directors?: {
|
|
107
|
+
name: string;
|
|
108
|
+
role?: string | undefined;
|
|
109
|
+
}[] | undefined;
|
|
110
|
+
shareholders?: {
|
|
111
|
+
name: string;
|
|
112
|
+
shares?: number | undefined;
|
|
113
|
+
}[] | undefined;
|
|
114
|
+
}, {
|
|
115
|
+
name: string;
|
|
116
|
+
status: string;
|
|
117
|
+
rcNumber: string;
|
|
118
|
+
source: string;
|
|
119
|
+
retrievedAt: string;
|
|
120
|
+
email?: string | null | undefined;
|
|
121
|
+
type?: string | null | undefined;
|
|
122
|
+
address?: string | null | undefined;
|
|
123
|
+
registrationDate?: string | null | undefined;
|
|
124
|
+
classification?: string | null | undefined;
|
|
125
|
+
directors?: {
|
|
126
|
+
name: string;
|
|
127
|
+
role?: string | undefined;
|
|
128
|
+
}[] | undefined;
|
|
129
|
+
shareholders?: {
|
|
130
|
+
name: string;
|
|
131
|
+
shares?: number | undefined;
|
|
132
|
+
}[] | undefined;
|
|
133
|
+
}>;
|
|
134
|
+
export type CompanyProfile = z.infer<typeof CompanyProfile>;
|
|
135
|
+
export declare const SearchHit: z.ZodObject<{
|
|
136
|
+
rcNumber: z.ZodString;
|
|
137
|
+
name: z.ZodString;
|
|
138
|
+
status: z.ZodString;
|
|
139
|
+
registrationDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
140
|
+
}, "strip", z.ZodTypeAny, {
|
|
141
|
+
name: string;
|
|
142
|
+
status: string;
|
|
143
|
+
rcNumber: string;
|
|
144
|
+
registrationDate?: string | null | undefined;
|
|
145
|
+
}, {
|
|
146
|
+
name: string;
|
|
147
|
+
status: string;
|
|
148
|
+
rcNumber: string;
|
|
149
|
+
registrationDate?: string | null | undefined;
|
|
150
|
+
}>;
|
|
151
|
+
export type SearchHit = z.infer<typeof SearchHit>;
|
|
152
|
+
export declare const NormalizedBankAccount: z.ZodObject<{
|
|
153
|
+
source: z.ZodString;
|
|
154
|
+
retrievedAt: z.ZodString;
|
|
155
|
+
accountNumber: z.ZodString;
|
|
156
|
+
accountName: z.ZodString;
|
|
157
|
+
bankCode: z.ZodString;
|
|
158
|
+
bankName: z.ZodOptional<z.ZodString>;
|
|
159
|
+
}, "strip", z.ZodTypeAny, {
|
|
160
|
+
source: string;
|
|
161
|
+
retrievedAt: string;
|
|
162
|
+
accountNumber: string;
|
|
163
|
+
accountName: string;
|
|
164
|
+
bankCode: string;
|
|
165
|
+
bankName?: string | undefined;
|
|
166
|
+
}, {
|
|
167
|
+
source: string;
|
|
168
|
+
retrievedAt: string;
|
|
169
|
+
accountNumber: string;
|
|
170
|
+
accountName: string;
|
|
171
|
+
bankCode: string;
|
|
172
|
+
bankName?: string | undefined;
|
|
173
|
+
}>;
|
|
174
|
+
export type NormalizedBankAccount = z.infer<typeof NormalizedBankAccount>;
|
|
175
|
+
export declare const FxRate: z.ZodObject<{
|
|
176
|
+
source: z.ZodString;
|
|
177
|
+
retrievedAt: z.ZodString;
|
|
178
|
+
base: z.ZodString;
|
|
179
|
+
quote: z.ZodString;
|
|
180
|
+
rate: z.ZodNumber;
|
|
181
|
+
market: z.ZodEnum<["official", "parallel"]>;
|
|
182
|
+
}, "strip", z.ZodTypeAny, {
|
|
183
|
+
source: string;
|
|
184
|
+
retrievedAt: string;
|
|
185
|
+
base: string;
|
|
186
|
+
quote: string;
|
|
187
|
+
rate: number;
|
|
188
|
+
market: "official" | "parallel";
|
|
189
|
+
}, {
|
|
190
|
+
source: string;
|
|
191
|
+
retrievedAt: string;
|
|
192
|
+
base: string;
|
|
193
|
+
quote: string;
|
|
194
|
+
rate: number;
|
|
195
|
+
market: "official" | "parallel";
|
|
196
|
+
}>;
|
|
197
|
+
export type FxRate = z.infer<typeof FxRate>;
|
|
198
|
+
export declare const NormalizedDriversLicense: z.ZodObject<{
|
|
199
|
+
source: z.ZodString;
|
|
200
|
+
retrievedAt: z.ZodString;
|
|
201
|
+
licenseNumber: z.ZodString;
|
|
202
|
+
holderName: z.ZodString;
|
|
203
|
+
status: z.ZodString;
|
|
204
|
+
issueDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
205
|
+
expiryDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
206
|
+
class: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
207
|
+
}, "strip", z.ZodTypeAny, {
|
|
208
|
+
status: string;
|
|
209
|
+
source: string;
|
|
210
|
+
retrievedAt: string;
|
|
211
|
+
licenseNumber: string;
|
|
212
|
+
holderName: string;
|
|
213
|
+
issueDate?: string | null | undefined;
|
|
214
|
+
expiryDate?: string | null | undefined;
|
|
215
|
+
class?: string | null | undefined;
|
|
216
|
+
}, {
|
|
217
|
+
status: string;
|
|
218
|
+
source: string;
|
|
219
|
+
retrievedAt: string;
|
|
220
|
+
licenseNumber: string;
|
|
221
|
+
holderName: string;
|
|
222
|
+
issueDate?: string | null | undefined;
|
|
223
|
+
expiryDate?: string | null | undefined;
|
|
224
|
+
class?: string | null | undefined;
|
|
225
|
+
}>;
|
|
226
|
+
export type NormalizedDriversLicense = z.infer<typeof NormalizedDriversLicense>;
|
|
227
|
+
export declare const NormalizedVehicle: z.ZodObject<{
|
|
228
|
+
source: z.ZodString;
|
|
229
|
+
retrievedAt: z.ZodString;
|
|
230
|
+
plateNumber: z.ZodString;
|
|
231
|
+
make: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
232
|
+
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
233
|
+
year: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
234
|
+
color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
235
|
+
fuel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
236
|
+
status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
237
|
+
}, "strip", z.ZodTypeAny, {
|
|
238
|
+
source: string;
|
|
239
|
+
retrievedAt: string;
|
|
240
|
+
plateNumber: string;
|
|
241
|
+
status?: string | null | undefined;
|
|
242
|
+
make?: string | null | undefined;
|
|
243
|
+
model?: string | null | undefined;
|
|
244
|
+
year?: number | null | undefined;
|
|
245
|
+
color?: string | null | undefined;
|
|
246
|
+
fuel?: string | null | undefined;
|
|
247
|
+
}, {
|
|
248
|
+
source: string;
|
|
249
|
+
retrievedAt: string;
|
|
250
|
+
plateNumber: string;
|
|
251
|
+
status?: string | null | undefined;
|
|
252
|
+
make?: string | null | undefined;
|
|
253
|
+
model?: string | null | undefined;
|
|
254
|
+
year?: number | null | undefined;
|
|
255
|
+
color?: string | null | undefined;
|
|
256
|
+
fuel?: string | null | undefined;
|
|
257
|
+
}>;
|
|
258
|
+
export type NormalizedVehicle = z.infer<typeof NormalizedVehicle>;
|
|
259
|
+
export declare const NormalizedMeter: z.ZodObject<{
|
|
260
|
+
source: z.ZodString;
|
|
261
|
+
retrievedAt: z.ZodString;
|
|
262
|
+
meterNumber: z.ZodString;
|
|
263
|
+
customerName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
264
|
+
address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
265
|
+
disco: z.ZodString;
|
|
266
|
+
meterType: z.ZodString;
|
|
267
|
+
}, "strip", z.ZodTypeAny, {
|
|
268
|
+
source: string;
|
|
269
|
+
retrievedAt: string;
|
|
270
|
+
meterNumber: string;
|
|
271
|
+
disco: string;
|
|
272
|
+
meterType: string;
|
|
273
|
+
address?: string | null | undefined;
|
|
274
|
+
customerName?: string | null | undefined;
|
|
275
|
+
}, {
|
|
276
|
+
source: string;
|
|
277
|
+
retrievedAt: string;
|
|
278
|
+
meterNumber: string;
|
|
279
|
+
disco: string;
|
|
280
|
+
meterType: string;
|
|
281
|
+
address?: string | null | undefined;
|
|
282
|
+
customerName?: string | null | undefined;
|
|
283
|
+
}>;
|
|
284
|
+
export type NormalizedMeter = z.infer<typeof NormalizedMeter>;
|
|
285
|
+
export declare const NormalizedCredential: z.ZodObject<{
|
|
286
|
+
source: z.ZodString;
|
|
287
|
+
retrievedAt: z.ZodString;
|
|
288
|
+
type: z.ZodString;
|
|
289
|
+
holderName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
290
|
+
institution: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
291
|
+
status: z.ZodString;
|
|
292
|
+
identifier: z.ZodString;
|
|
293
|
+
}, "strip", z.ZodTypeAny, {
|
|
294
|
+
type: string;
|
|
295
|
+
status: string;
|
|
296
|
+
source: string;
|
|
297
|
+
retrievedAt: string;
|
|
298
|
+
identifier: string;
|
|
299
|
+
holderName?: string | null | undefined;
|
|
300
|
+
institution?: string | null | undefined;
|
|
301
|
+
}, {
|
|
302
|
+
type: string;
|
|
303
|
+
status: string;
|
|
304
|
+
source: string;
|
|
305
|
+
retrievedAt: string;
|
|
306
|
+
identifier: string;
|
|
307
|
+
holderName?: string | null | undefined;
|
|
308
|
+
institution?: string | null | undefined;
|
|
309
|
+
}>;
|
|
310
|
+
export type NormalizedCredential = z.infer<typeof NormalizedCredential>;
|
|
311
|
+
export declare const NormalizedTradeFlow: z.ZodObject<{
|
|
312
|
+
source: z.ZodString;
|
|
313
|
+
retrievedAt: z.ZodString;
|
|
314
|
+
reporter: z.ZodString;
|
|
315
|
+
partner: z.ZodString;
|
|
316
|
+
hsCode: z.ZodString;
|
|
317
|
+
commodity: z.ZodString;
|
|
318
|
+
flow: z.ZodEnum<["import", "export"]>;
|
|
319
|
+
period: z.ZodString;
|
|
320
|
+
year: z.ZodNumber;
|
|
321
|
+
valueUsd: z.ZodNumber;
|
|
322
|
+
cifValueUsd: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
323
|
+
fobValueUsd: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
324
|
+
netWeightKg: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
325
|
+
quantity: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
326
|
+
quantityUnit: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
327
|
+
}, "strip", z.ZodTypeAny, {
|
|
328
|
+
source: string;
|
|
329
|
+
retrievedAt: string;
|
|
330
|
+
year: number;
|
|
331
|
+
reporter: string;
|
|
332
|
+
partner: string;
|
|
333
|
+
hsCode: string;
|
|
334
|
+
commodity: string;
|
|
335
|
+
flow: "import" | "export";
|
|
336
|
+
period: string;
|
|
337
|
+
valueUsd: number;
|
|
338
|
+
cifValueUsd?: number | null | undefined;
|
|
339
|
+
fobValueUsd?: number | null | undefined;
|
|
340
|
+
netWeightKg?: number | null | undefined;
|
|
341
|
+
quantity?: number | null | undefined;
|
|
342
|
+
quantityUnit?: string | null | undefined;
|
|
343
|
+
}, {
|
|
344
|
+
source: string;
|
|
345
|
+
retrievedAt: string;
|
|
346
|
+
year: number;
|
|
347
|
+
reporter: string;
|
|
348
|
+
partner: string;
|
|
349
|
+
hsCode: string;
|
|
350
|
+
commodity: string;
|
|
351
|
+
flow: "import" | "export";
|
|
352
|
+
period: string;
|
|
353
|
+
valueUsd: number;
|
|
354
|
+
cifValueUsd?: number | null | undefined;
|
|
355
|
+
fobValueUsd?: number | null | undefined;
|
|
356
|
+
netWeightKg?: number | null | undefined;
|
|
357
|
+
quantity?: number | null | undefined;
|
|
358
|
+
quantityUnit?: string | null | undefined;
|
|
359
|
+
}>;
|
|
360
|
+
export type NormalizedTradeFlow = z.infer<typeof NormalizedTradeFlow>;
|
|
361
|
+
export declare const NormalizedHsCode: z.ZodObject<{
|
|
362
|
+
source: z.ZodString;
|
|
363
|
+
retrievedAt: z.ZodString;
|
|
364
|
+
query: z.ZodString;
|
|
365
|
+
hsCode: z.ZodString;
|
|
366
|
+
heading: z.ZodString;
|
|
367
|
+
}, "strip", z.ZodTypeAny, {
|
|
368
|
+
source: string;
|
|
369
|
+
retrievedAt: string;
|
|
370
|
+
hsCode: string;
|
|
371
|
+
query: string;
|
|
372
|
+
heading: string;
|
|
373
|
+
}, {
|
|
374
|
+
source: string;
|
|
375
|
+
retrievedAt: string;
|
|
376
|
+
hsCode: string;
|
|
377
|
+
query: string;
|
|
378
|
+
heading: string;
|
|
379
|
+
}>;
|
|
380
|
+
export type NormalizedHsCode = z.infer<typeof NormalizedHsCode>;
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized, agent-facing data contracts. The SAME shape is returned regardless of
|
|
3
|
+
* which upstream provider served the request — this stability is the product.
|
|
4
|
+
* See brain/04-rules/engineering-rules.md and the lane dossiers in brain/07-lanes/.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
/** Provenance fields stamped onto every normalized record. */
|
|
8
|
+
export const Provenance = {
|
|
9
|
+
source: z.string().describe("Which provider/source served this record (e.g. 'mock', 'public', 'mono')"),
|
|
10
|
+
retrievedAt: z.string().describe("ISO-8601 timestamp when the record was fetched"),
|
|
11
|
+
};
|
|
12
|
+
// ---------- CAC / KYB ----------
|
|
13
|
+
export const NormalizedCompany = z.object({
|
|
14
|
+
rcNumber: z.string().describe("CAC registration (RC) number"),
|
|
15
|
+
name: z.string().describe("Registered company name"),
|
|
16
|
+
status: z.string().describe("Registration status, e.g. ACTIVE / INACTIVE"),
|
|
17
|
+
address: z.string().nullable().optional().describe("Registered address"),
|
|
18
|
+
registrationDate: z.string().nullable().optional().describe("Date of incorporation (ISO date)"),
|
|
19
|
+
type: z.string().nullable().optional().describe("Entity type, e.g. LTD / BN / IT"),
|
|
20
|
+
...Provenance,
|
|
21
|
+
});
|
|
22
|
+
export const Director = z.object({
|
|
23
|
+
name: z.string(),
|
|
24
|
+
role: z.string().optional(),
|
|
25
|
+
});
|
|
26
|
+
export const Shareholder = z.object({
|
|
27
|
+
name: z.string(),
|
|
28
|
+
shares: z.number().optional(),
|
|
29
|
+
});
|
|
30
|
+
export const CompanyProfile = NormalizedCompany.extend({
|
|
31
|
+
classification: z.string().nullable().optional(),
|
|
32
|
+
email: z.string().nullable().optional(),
|
|
33
|
+
directors: z.array(Director).optional(),
|
|
34
|
+
shareholders: z.array(Shareholder).optional(),
|
|
35
|
+
});
|
|
36
|
+
export const SearchHit = z.object({
|
|
37
|
+
rcNumber: z.string(),
|
|
38
|
+
name: z.string(),
|
|
39
|
+
status: z.string(),
|
|
40
|
+
registrationDate: z.string().nullable().optional(),
|
|
41
|
+
});
|
|
42
|
+
// ---------- Bank ----------
|
|
43
|
+
export const NormalizedBankAccount = z.object({
|
|
44
|
+
accountNumber: z.string().describe("10-digit NUBAN"),
|
|
45
|
+
accountName: z.string().describe("Registered account holder name"),
|
|
46
|
+
bankCode: z.string(),
|
|
47
|
+
bankName: z.string().optional(),
|
|
48
|
+
...Provenance,
|
|
49
|
+
});
|
|
50
|
+
// ---------- FX ----------
|
|
51
|
+
export const FxRate = z.object({
|
|
52
|
+
base: z.string().describe("Base currency, e.g. NGN"),
|
|
53
|
+
quote: z.string().describe("Quote currency, e.g. USD"),
|
|
54
|
+
rate: z.number(),
|
|
55
|
+
market: z.enum(["official", "parallel"]).describe("Official (CBN) or parallel ('aboki') market"),
|
|
56
|
+
...Provenance,
|
|
57
|
+
});
|
|
58
|
+
// ---------- Driver's licence + vehicle (FRSC) ----------
|
|
59
|
+
// PII pass-through only — never persisted/cached (NDPA). Optional fields are provider-dependent.
|
|
60
|
+
export const NormalizedDriversLicense = z.object({
|
|
61
|
+
licenseNumber: z.string().describe("Driver's licence number"),
|
|
62
|
+
holderName: z.string().describe("Licence holder's full name"),
|
|
63
|
+
status: z.string().describe("Validity status, e.g. VALID / EXPIRED"),
|
|
64
|
+
issueDate: z.string().nullable().optional().describe("Issue date (ISO)"),
|
|
65
|
+
expiryDate: z.string().nullable().optional().describe("Expiry date (ISO)"),
|
|
66
|
+
class: z.string().nullable().optional().describe("Licence class, e.g. A / B / C"),
|
|
67
|
+
...Provenance,
|
|
68
|
+
});
|
|
69
|
+
export const NormalizedVehicle = z.object({
|
|
70
|
+
plateNumber: z.string().describe("Vehicle plate number (normalized, uppercase)"),
|
|
71
|
+
make: z.string().nullable().optional(),
|
|
72
|
+
model: z.string().nullable().optional(),
|
|
73
|
+
year: z.number().nullable().optional(),
|
|
74
|
+
color: z.string().nullable().optional(),
|
|
75
|
+
fuel: z.string().nullable().optional(),
|
|
76
|
+
status: z.string().nullable().optional().describe("Registration status, e.g. REGISTERED / EXPIRED"),
|
|
77
|
+
...Provenance,
|
|
78
|
+
});
|
|
79
|
+
// ---------- Electricity / meter validation (READ-ONLY) ----------
|
|
80
|
+
// Validation/info only — never payment execution (NERC/CBN/AML). Customer PII not persisted.
|
|
81
|
+
export const NormalizedMeter = z.object({
|
|
82
|
+
meterNumber: z.string().describe("Electricity meter number"),
|
|
83
|
+
customerName: z.string().nullable().optional().describe("Registered customer name (PII — pass-through)"),
|
|
84
|
+
address: z.string().nullable().optional().describe("Service address (PII — pass-through)"),
|
|
85
|
+
disco: z.string().describe("Distribution company code, e.g. EKEDC / IKEDC / AEDC / PHED"),
|
|
86
|
+
meterType: z.string().describe("prepaid | postpaid"),
|
|
87
|
+
...Provenance,
|
|
88
|
+
});
|
|
89
|
+
// ---------- Education / credential verification (KYE) ----------
|
|
90
|
+
// Verify via licensed aggregators (they carry NDPR) — never scrape WAEC/JAMB. PII pass-through.
|
|
91
|
+
export const NormalizedCredential = z.object({
|
|
92
|
+
type: z.string().describe("Credential type, e.g. WAEC / NECO / NYSC / DEGREE / TRCN"),
|
|
93
|
+
holderName: z.string().nullable().optional().describe("Credential holder name (PII — pass-through)"),
|
|
94
|
+
institution: z.string().nullable().optional().describe("Issuing institution / body"),
|
|
95
|
+
status: z.string().describe("Verification status, e.g. VERIFIED / REGISTERED / NOT_FOUND"),
|
|
96
|
+
identifier: z.string().describe("The certificate / exam / registration number verified"),
|
|
97
|
+
...Provenance,
|
|
98
|
+
});
|
|
99
|
+
// ---------- Trade intelligence (public macro data, no PII) ----------
|
|
100
|
+
export const NormalizedTradeFlow = z.object({
|
|
101
|
+
reporter: z.string().describe("Reporting country, e.g. Nigeria"),
|
|
102
|
+
partner: z.string().describe("Trade partner country"),
|
|
103
|
+
hsCode: z.string().describe("HS commodity code (or aggregate, e.g. TOTAL)"),
|
|
104
|
+
commodity: z.string().describe("Commodity description"),
|
|
105
|
+
flow: z.enum(["import", "export"]),
|
|
106
|
+
period: z.string().describe("Reporting period — year (2024) or year-month (202403)"),
|
|
107
|
+
year: z.number().describe("Reporting year"),
|
|
108
|
+
valueUsd: z.number().describe("Primary trade value in USD"),
|
|
109
|
+
cifValueUsd: z.number().nullable().optional().describe("CIF value in USD (imports), where reported"),
|
|
110
|
+
fobValueUsd: z.number().nullable().optional().describe("FOB value in USD (exports), where reported"),
|
|
111
|
+
netWeightKg: z.number().nullable().optional().describe("Net weight in kilograms, where reported"),
|
|
112
|
+
quantity: z.number().nullable().optional().describe("Quantity in the reported unit, where available"),
|
|
113
|
+
quantityUnit: z.string().nullable().optional().describe("Unit for quantity, e.g. 'N' (number of items), 'kg', 'l'"),
|
|
114
|
+
...Provenance,
|
|
115
|
+
});
|
|
116
|
+
export const NormalizedHsCode = z.object({
|
|
117
|
+
query: z.string().describe("The product description that was classified"),
|
|
118
|
+
hsCode: z.string().describe("Best-match HS code"),
|
|
119
|
+
heading: z.string().describe("HS heading / description"),
|
|
120
|
+
...Provenance,
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-agnostic MCP server builder. Lanes hand buildServer() an array of ToolDefs;
|
|
3
|
+
* stdio.ts and http.ts wrap the result in a transport. See brain/05-plans/v1-plan.md
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { type ZodRawShape } from "zod";
|
|
8
|
+
export interface ToolAnnotations {
|
|
9
|
+
readOnlyHint?: boolean;
|
|
10
|
+
openWorldHint?: boolean;
|
|
11
|
+
idempotentHint?: boolean;
|
|
12
|
+
destructiveHint?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ToolDef {
|
|
15
|
+
name: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
description: string;
|
|
18
|
+
inputSchema: ZodRawShape;
|
|
19
|
+
outputSchema?: ZodRawShape;
|
|
20
|
+
annotations?: ToolAnnotations;
|
|
21
|
+
handler: (args: Record<string, unknown>) => Promise<CallToolResult>;
|
|
22
|
+
}
|
|
23
|
+
export interface BuildServerOptions {
|
|
24
|
+
name?: string;
|
|
25
|
+
version?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function buildServer(tools: ToolDef[], opts?: BuildServerOptions): McpServer;
|
|
28
|
+
/** Throwaway health tool used to smoke-test transports. Safe to keep; harmless. */
|
|
29
|
+
export declare const pingTool: ToolDef;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-agnostic MCP server builder. Lanes hand buildServer() an array of ToolDefs;
|
|
3
|
+
* stdio.ts and http.ts wrap the result in a transport. See brain/05-plans/v1-plan.md
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { toToolResult } from "./lib/errors.js";
|
|
8
|
+
import { nowIso } from "./lib/normalize.js";
|
|
9
|
+
export function buildServer(tools, opts = {}) {
|
|
10
|
+
const server = new McpServer({
|
|
11
|
+
name: opts.name ?? "nigeria-mcp",
|
|
12
|
+
version: opts.version ?? "0.0.0",
|
|
13
|
+
});
|
|
14
|
+
for (const tool of tools) {
|
|
15
|
+
server.registerTool(tool.name, {
|
|
16
|
+
title: tool.title ?? tool.name,
|
|
17
|
+
description: tool.description,
|
|
18
|
+
inputSchema: tool.inputSchema,
|
|
19
|
+
outputSchema: tool.outputSchema,
|
|
20
|
+
// Lookup tools are read-only and talk to the outside world by default.
|
|
21
|
+
annotations: { readOnlyHint: true, openWorldHint: true, ...tool.annotations },
|
|
22
|
+
// Cast at the SDK boundary: the generic ties the callback to the inferred schema,
|
|
23
|
+
// but our ToolDef handler uses a uniform Record signature.
|
|
24
|
+
}, (async (args) => {
|
|
25
|
+
try {
|
|
26
|
+
return await tool.handler(args ?? {});
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
return toToolResult(err);
|
|
30
|
+
}
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
return server;
|
|
34
|
+
}
|
|
35
|
+
/** Throwaway health tool used to smoke-test transports. Safe to keep; harmless. */
|
|
36
|
+
export const pingTool = {
|
|
37
|
+
name: "ping",
|
|
38
|
+
title: "Ping",
|
|
39
|
+
description: "Health check — returns pong and the server time.",
|
|
40
|
+
inputSchema: {},
|
|
41
|
+
outputSchema: { pong: z.boolean(), time: z.string() },
|
|
42
|
+
handler: async () => {
|
|
43
|
+
const time = nowIso();
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: `pong @ ${time}` }],
|
|
46
|
+
structuredContent: { pong: true, time },
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,CAAC,EAAoB,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAwB5C,MAAM,UAAU,WAAW,CAAC,KAAgB,EAAE,OAA2B,EAAE;IACzE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,aAAa;QAChC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,OAAO;KACjC,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI;YAC9B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,uEAAuE;YACvE,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE;YAC7E,kFAAkF;YAClF,2DAA2D;SAChB,EAC7C,CAAC,KAAK,EAAE,IAA6B,EAAE,EAAE;YACvC,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACxC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC,CAA6C,CAC/C,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,MAAM,QAAQ,GAAY;IAC/B,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,WAAW,EAAE,kDAAkD;IAC/D,WAAW,EAAE,EAAE;IACf,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;IACrD,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;QACtB,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,IAAI,EAAE,EAAE,CAAC;YACnD,iBAAiB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;SACxC,CAAC;IACJ,CAAC;CACF,CAAC"}
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/stdio.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core stdio entrypoint — ships only the ping tool. Lanes provide their own entrypoints
|
|
3
|
+
* that pass their tools to startStdio().
|
|
4
|
+
*/
|
|
5
|
+
import { startStdio } from "./runtime.js";
|
|
6
|
+
import { pingTool } from "./server.js";
|
|
7
|
+
await startStdio([pingTool]);
|
|
8
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@braynexservices/nigeria-mcp-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core runtime for the Nigeria MCP data-lane servers: MCP server builder, normalized Zod schemas, typed provider seam, and shared fetch/cache/error helpers.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"publishConfig": { "access": "public" },
|
|
7
|
+
"files": ["dist", "LICENSE", "NOTICE"],
|
|
8
|
+
"homepage": "https://www.braynexservices.com",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/braynexservices/nigeria-mcp.git",
|
|
12
|
+
"directory": "shared"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"prepack": "tsc",
|
|
26
|
+
"start:stdio": "tsx src/stdio.ts",
|
|
27
|
+
"start:http": "tsx src/http.ts",
|
|
28
|
+
"smoke": "tsx scripts/smoke.ts",
|
|
29
|
+
"inspect": "mcp-inspector tsx src/stdio.ts"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
33
|
+
"express": "^4.22.2",
|
|
34
|
+
"zod": "^3.25.76"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/express": "^4.17.25",
|
|
38
|
+
"@types/node": "^26.0.0",
|
|
39
|
+
"tsx": "^4.22.4",
|
|
40
|
+
"typescript": "^6.0.3"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"author": "Samuel Orie <braynexservices@gmail.com> (Braynex Services Ltd — https://www.braynexservices.com)"
|
|
44
|
+
}
|