nextbillion-mcp 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/dist/config.d.ts +11 -0
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -0
- package/dist/core/server.d.ts +13 -0
- package/dist/core/server.js +62 -0
- package/dist/core/server.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.js +13 -0
- package/dist/log.js.map +1 -0
- package/dist/nbclient/client.d.ts +39 -0
- package/dist/nbclient/client.js +124 -0
- package/dist/nbclient/client.js.map +1 -0
- package/dist/nbclient/errors.d.ts +13 -0
- package/dist/nbclient/errors.js +36 -0
- package/dist/nbclient/errors.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.js +35 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/maps/static-map-image.d.ts +25 -0
- package/dist/tools/maps/static-map-image.js +31 -0
- package/dist/tools/maps/static-map-image.js.map +1 -0
- package/dist/tools/maps/static-route-map.d.ts +28 -0
- package/dist/tools/maps/static-route-map.js +71 -0
- package/dist/tools/maps/static-route-map.js.map +1 -0
- package/dist/tools/maps/static-shared.d.ts +32 -0
- package/dist/tools/maps/static-shared.js +57 -0
- package/dist/tools/maps/static-shared.js.map +1 -0
- package/dist/tools/places/geocode-batch.d.ts +35 -0
- package/dist/tools/places/geocode-batch.js +52 -0
- package/dist/tools/places/geocode-batch.js.map +1 -0
- package/dist/tools/places/geocode-reverse.d.ts +30 -0
- package/dist/tools/places/geocode-reverse.js +33 -0
- package/dist/tools/places/geocode-reverse.js.map +1 -0
- package/dist/tools/places/geocode-structured.d.ts +32 -0
- package/dist/tools/places/geocode-structured.js +59 -0
- package/dist/tools/places/geocode-structured.js.map +1 -0
- package/dist/tools/places/place-lookup.d.ts +19 -0
- package/dist/tools/places/place-lookup.js +24 -0
- package/dist/tools/places/place-lookup.js.map +1 -0
- package/dist/tools/places/postcode-lookup.d.ts +13 -0
- package/dist/tools/places/postcode-lookup.js +56 -0
- package/dist/tools/places/postcode-lookup.js.map +1 -0
- package/dist/tools/places/text-search.d.ts +118 -0
- package/dist/tools/places/text-search.js +66 -0
- package/dist/tools/places/text-search.js.map +1 -0
- package/dist/tools/routing/directions.d.ts +58 -0
- package/dist/tools/routing/directions.js +109 -0
- package/dist/tools/routing/directions.js.map +1 -0
- package/dist/tools/routing/distance-matrix.d.ts +42 -0
- package/dist/tools/routing/distance-matrix.js +76 -0
- package/dist/tools/routing/distance-matrix.js.map +1 -0
- package/dist/tools/routing/isochrone.d.ts +22 -0
- package/dist/tools/routing/isochrone.js +67 -0
- package/dist/tools/routing/isochrone.js.map +1 -0
- package/dist/tools/routing/search-along-route.d.ts +17 -0
- package/dist/tools/routing/search-along-route.js +58 -0
- package/dist/tools/routing/search-along-route.js.map +1 -0
- package/dist/tools/shared/geo.d.ts +81 -0
- package/dist/tools/shared/geo.js +94 -0
- package/dist/tools/shared/geo.js.map +1 -0
- package/dist/tools/types.d.ts +39 -0
- package/dist/tools/types.js +13 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +49 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ServerConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
timeoutMs: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const DEFAULT_BASE_URL = "https://api.nextbillion.io";
|
|
7
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
8
|
+
export declare class ConfigError extends Error {
|
|
9
|
+
}
|
|
10
|
+
/** Read configuration from environment variables. Throws ConfigError when the API key is missing. */
|
|
11
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): ServerConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const DEFAULT_BASE_URL = 'https://api.nextbillion.io';
|
|
2
|
+
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
3
|
+
export class ConfigError extends Error {
|
|
4
|
+
}
|
|
5
|
+
/** Read configuration from environment variables. Throws ConfigError when the API key is missing. */
|
|
6
|
+
export function loadConfig(env = process.env) {
|
|
7
|
+
const apiKey = env.NBAI_API_KEY?.trim();
|
|
8
|
+
if (!apiKey) {
|
|
9
|
+
throw new ConfigError('NBAI_API_KEY is not set. Get an API key at https://console.nextbillion.ai and ' +
|
|
10
|
+
'expose it to the server, e.g. NBAI_API_KEY=<your key> npx nextbillion-mcp');
|
|
11
|
+
}
|
|
12
|
+
const timeoutMs = env.NBAI_TIMEOUT_MS ? Number(env.NBAI_TIMEOUT_MS) : DEFAULT_TIMEOUT_MS;
|
|
13
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
14
|
+
throw new ConfigError(`NBAI_TIMEOUT_MS must be a positive number, got: ${env.NBAI_TIMEOUT_MS}`);
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
apiKey,
|
|
18
|
+
baseUrl: (env.NBAI_BASE_URL?.trim() || DEFAULT_BASE_URL).replace(/\/+$/, ''),
|
|
19
|
+
timeoutMs,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAC7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC,MAAM,OAAO,WAAY,SAAQ,KAAK;CAAG;AAEzC,qGAAqG;AACrG,MAAM,UAAU,UAAU,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IAC7D,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,WAAW,CACnB,gFAAgF;YAC9E,2EAA2E,CAC9E,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACzF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,WAAW,CAAC,mDAAmD,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,OAAO;QACL,MAAM;QACN,OAAO,EAAE,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5E,SAAS;KACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
+
import type { NbClient } from '../nbclient/client.js';
|
|
3
|
+
export declare const SERVER_NAME = "nextbillion-mcp";
|
|
4
|
+
/**
|
|
5
|
+
* Build one McpServer instance wired to the given NextBillion API client.
|
|
6
|
+
* Used as the per-connection factory for serveStdio (and later HTTP serving).
|
|
7
|
+
*
|
|
8
|
+
* 2026-07-28 spec notes: the SDK provides server/discover, per-request _meta
|
|
9
|
+
* validation, and resultType stamping. The deprecated Roots/Sampling/Logging
|
|
10
|
+
* features are intentionally not implemented. The tool list is static, so
|
|
11
|
+
* tools/list advertises a 24h public cache hint.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildServer(nb: NbClient, version: string): McpServer;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
+
import { NbApiError } from '../nbclient/errors.js';
|
|
3
|
+
import { ALL_TOOLS } from '../tools/index.js';
|
|
4
|
+
import { ToolInputError } from '../tools/types.js';
|
|
5
|
+
import { logError } from '../log.js';
|
|
6
|
+
export const SERVER_NAME = 'nextbillion-mcp';
|
|
7
|
+
/**
|
|
8
|
+
* Build one McpServer instance wired to the given NextBillion API client.
|
|
9
|
+
* Used as the per-connection factory for serveStdio (and later HTTP serving).
|
|
10
|
+
*
|
|
11
|
+
* 2026-07-28 spec notes: the SDK provides server/discover, per-request _meta
|
|
12
|
+
* validation, and resultType stamping. The deprecated Roots/Sampling/Logging
|
|
13
|
+
* features are intentionally not implemented. The tool list is static, so
|
|
14
|
+
* tools/list advertises a 24h public cache hint.
|
|
15
|
+
*/
|
|
16
|
+
export function buildServer(nb, version) {
|
|
17
|
+
const server = new McpServer({ name: SERVER_NAME, version }, {
|
|
18
|
+
capabilities: { tools: {} },
|
|
19
|
+
cacheHints: {
|
|
20
|
+
'tools/list': { ttlMs: 86_400_000, cacheScope: 'public' },
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
for (const tool of ALL_TOOLS) {
|
|
24
|
+
server.registerTool(tool.name, {
|
|
25
|
+
title: tool.title,
|
|
26
|
+
description: tool.description,
|
|
27
|
+
inputSchema: tool.inputSchema,
|
|
28
|
+
annotations: tool.annotations,
|
|
29
|
+
}, async (args) => {
|
|
30
|
+
try {
|
|
31
|
+
return await tool.run(args, nb);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
return toToolError(tool.name, error);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return server;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Upstream API failures and input validation problems come back as ordinary tool
|
|
42
|
+
* results with isError, so the model can read the message and correct its call.
|
|
43
|
+
*/
|
|
44
|
+
function toToolError(toolName, error) {
|
|
45
|
+
if (error instanceof ToolInputError) {
|
|
46
|
+
return { content: [{ type: 'text', text: `Invalid input: ${error.message}` }], isError: true };
|
|
47
|
+
}
|
|
48
|
+
if (error instanceof NbApiError) {
|
|
49
|
+
return { content: [{ type: 'text', text: error.message }], isError: true };
|
|
50
|
+
}
|
|
51
|
+
logError(`Unexpected error in tool ${toolName}`, error);
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: 'text',
|
|
56
|
+
text: `Unexpected error in ${toolName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
isError: true,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAmB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,EAAY,EAAE,OAAe;IACvD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAC9B;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B,UAAU,EAAE;YACV,YAAY,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE;SAC1D;KACF,CACF,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,EACD,KAAK,EAAE,IAAa,EAAuB,EAAE;YAC3C,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,IAAa,EAAE,EAAE,CAAC,CAAC;YAC3C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACvC,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,QAAgB,EAAE,KAAc;IACnD,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;QACpC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACjG,CAAC;IACD,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7E,CAAC;IACD,QAAQ,CAAC,4BAA4B,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;IACxD,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,uBAAuB,QAAQ,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;aACnG;SACF;QACD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { serveStdio } from '@modelcontextprotocol/server/stdio';
|
|
4
|
+
import { ConfigError, loadConfig } from './config.js';
|
|
5
|
+
import { buildServer, SERVER_NAME } from './core/server.js';
|
|
6
|
+
import { logError, logInfo } from './log.js';
|
|
7
|
+
import { NbClient } from './nbclient/client.js';
|
|
8
|
+
const pkg = createRequire(import.meta.url)('../package.json');
|
|
9
|
+
function main() {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
12
|
+
console.log(pkg.version);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
16
|
+
console.log(`${SERVER_NAME} ${pkg.version} — MCP server for NextBillion.ai location APIs\n\n` +
|
|
17
|
+
'Runs as an MCP stdio server; configure it in your MCP client, not by hand.\n\n' +
|
|
18
|
+
'Environment variables:\n' +
|
|
19
|
+
' NBAI_API_KEY (required) NextBillion.ai API key\n' +
|
|
20
|
+
' NBAI_BASE_URL (optional) API base URL, default https://api.nextbillion.io\n' +
|
|
21
|
+
' NBAI_TIMEOUT_MS (optional) per-request timeout, default 30000\n');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
let config;
|
|
25
|
+
try {
|
|
26
|
+
config = loadConfig();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error instanceof ConfigError) {
|
|
30
|
+
logError(error.message);
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
const nb = new NbClient({
|
|
37
|
+
apiKey: config.apiKey,
|
|
38
|
+
baseUrl: config.baseUrl,
|
|
39
|
+
timeoutMs: config.timeoutMs,
|
|
40
|
+
});
|
|
41
|
+
const handle = serveStdio(() => buildServer(nb, pkg.version));
|
|
42
|
+
logInfo(`${SERVER_NAME} ${pkg.version} listening on stdio`);
|
|
43
|
+
const shutdown = () => {
|
|
44
|
+
void handle.close().finally(() => process.exit(0));
|
|
45
|
+
};
|
|
46
|
+
process.on('SIGINT', shutdown);
|
|
47
|
+
process.on('SIGTERM', shutdown);
|
|
48
|
+
}
|
|
49
|
+
main();
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAwB,CAAC;AAErF,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CACT,GAAG,WAAW,IAAI,GAAG,CAAC,OAAO,oDAAoD;YAC/E,gFAAgF;YAChF,0BAA0B;YAC1B,yDAAyD;YACzD,mFAAmF;YACnF,qEAAqE,CACxE,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,WAAW,IAAI,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC"}
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stdout is the JSON-RPC channel on stdio transports, so all logging goes to stderr.
|
|
3
|
+
* The MCP `logging` capability is deprecated in the 2026-07-28 revision; stderr is
|
|
4
|
+
* the recommended channel for locally-spawned servers.
|
|
5
|
+
*/
|
|
6
|
+
export declare function logError(message: string, error?: unknown): void;
|
|
7
|
+
export declare function logInfo(message: string): void;
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stdout is the JSON-RPC channel on stdio transports, so all logging goes to stderr.
|
|
3
|
+
* The MCP `logging` capability is deprecated in the 2026-07-28 revision; stderr is
|
|
4
|
+
* the recommended channel for locally-spawned servers.
|
|
5
|
+
*/
|
|
6
|
+
export function logError(message, error) {
|
|
7
|
+
const detail = error instanceof Error ? `: ${error.message}` : error ? `: ${String(error)}` : '';
|
|
8
|
+
console.error(`[nextbillion-mcp] ${message}${detail}`);
|
|
9
|
+
}
|
|
10
|
+
export function logInfo(message) {
|
|
11
|
+
console.error(`[nextbillion-mcp] ${message}`);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=log.js.map
|
package/dist/log.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,KAAe;IACvD,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACjG,OAAO,CAAC,KAAK,CAAC,qBAAqB,OAAO,GAAG,MAAM,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,OAAO,CAAC,KAAK,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type QueryValue = string | number | boolean | undefined;
|
|
2
|
+
/** Arrays produce repeated query parameters (e.g. several `path=` entries). */
|
|
3
|
+
export type Query = Record<string, QueryValue | QueryValue[]>;
|
|
4
|
+
export interface NbClientOptions {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
/** Injectable for tests. Defaults to global fetch. */
|
|
9
|
+
fetchFn?: typeof fetch;
|
|
10
|
+
/** Max retries for 429/5xx/network failures on idempotent requests. */
|
|
11
|
+
maxRetries?: number;
|
|
12
|
+
/** Injectable for tests. Defaults to a real delay. */
|
|
13
|
+
sleepFn?: (ms: number) => Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export interface BinaryResponse {
|
|
16
|
+
data: Uint8Array;
|
|
17
|
+
contentType: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Single HTTP client shared by every tool: injects the API key, applies timeouts,
|
|
21
|
+
* retries transient failures with backoff, and normalizes errors. All NextBillion
|
|
22
|
+
* endpoints authenticate via the `key` query parameter.
|
|
23
|
+
*/
|
|
24
|
+
export declare class NbClient {
|
|
25
|
+
private readonly apiKey;
|
|
26
|
+
private readonly baseUrl;
|
|
27
|
+
private readonly timeoutMs;
|
|
28
|
+
private readonly fetchFn;
|
|
29
|
+
private readonly maxRetries;
|
|
30
|
+
private readonly sleepFn;
|
|
31
|
+
constructor(options: NbClientOptions);
|
|
32
|
+
buildUrl(path: string, query?: Query): string;
|
|
33
|
+
getJson<T = unknown>(path: string, query?: Query): Promise<T>;
|
|
34
|
+
postJson<T = unknown>(path: string, query: Query, body: unknown): Promise<T>;
|
|
35
|
+
getBinary(path: string, query?: Query): Promise<BinaryResponse>;
|
|
36
|
+
private request;
|
|
37
|
+
private backoffMs;
|
|
38
|
+
private parseJson;
|
|
39
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { NbApiError, redactKey } from './errors.js';
|
|
2
|
+
const RETRIABLE_STATUSES = new Set([429, 502, 503, 504]);
|
|
3
|
+
function sleep(ms) {
|
|
4
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Single HTTP client shared by every tool: injects the API key, applies timeouts,
|
|
8
|
+
* retries transient failures with backoff, and normalizes errors. All NextBillion
|
|
9
|
+
* endpoints authenticate via the `key` query parameter.
|
|
10
|
+
*/
|
|
11
|
+
export class NbClient {
|
|
12
|
+
apiKey;
|
|
13
|
+
baseUrl;
|
|
14
|
+
timeoutMs;
|
|
15
|
+
fetchFn;
|
|
16
|
+
maxRetries;
|
|
17
|
+
sleepFn;
|
|
18
|
+
constructor(options) {
|
|
19
|
+
this.apiKey = options.apiKey;
|
|
20
|
+
this.baseUrl = (options.baseUrl ?? 'https://api.nextbillion.io').replace(/\/+$/, '');
|
|
21
|
+
this.timeoutMs = options.timeoutMs ?? 30_000;
|
|
22
|
+
this.fetchFn = options.fetchFn ?? fetch;
|
|
23
|
+
this.maxRetries = options.maxRetries ?? 2;
|
|
24
|
+
this.sleepFn = options.sleepFn ?? sleep;
|
|
25
|
+
}
|
|
26
|
+
buildUrl(path, query = {}) {
|
|
27
|
+
const url = new URL(this.baseUrl + path);
|
|
28
|
+
url.searchParams.set('key', this.apiKey);
|
|
29
|
+
for (const [name, value] of Object.entries(query)) {
|
|
30
|
+
for (const entry of Array.isArray(value) ? value : [value]) {
|
|
31
|
+
if (entry !== undefined)
|
|
32
|
+
url.searchParams.append(name, String(entry));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return url.toString();
|
|
36
|
+
}
|
|
37
|
+
async getJson(path, query = {}) {
|
|
38
|
+
const response = await this.request('GET', this.buildUrl(path, query));
|
|
39
|
+
return this.parseJson(response);
|
|
40
|
+
}
|
|
41
|
+
async postJson(path, query, body) {
|
|
42
|
+
const response = await this.request('POST', this.buildUrl(path, query), body);
|
|
43
|
+
return this.parseJson(response);
|
|
44
|
+
}
|
|
45
|
+
async getBinary(path, query = {}) {
|
|
46
|
+
const response = await this.request('GET', this.buildUrl(path, query));
|
|
47
|
+
return {
|
|
48
|
+
data: new Uint8Array(await response.arrayBuffer()),
|
|
49
|
+
contentType: response.headers.get('content-type') ?? 'application/octet-stream',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async request(method, url, body) {
|
|
53
|
+
// POST bodies here are all idempotent queries (search/matrix/geocode), so retrying is safe.
|
|
54
|
+
let lastError;
|
|
55
|
+
for (let attempt = 0;; attempt++) {
|
|
56
|
+
let response;
|
|
57
|
+
try {
|
|
58
|
+
response = await this.fetchFn(url, {
|
|
59
|
+
method,
|
|
60
|
+
headers: body !== undefined ? { 'Content-Type': 'application/json' } : undefined,
|
|
61
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
62
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const timedOut = error instanceof DOMException && error.name === 'TimeoutError';
|
|
67
|
+
lastError = new NbApiError({
|
|
68
|
+
url,
|
|
69
|
+
message: timedOut
|
|
70
|
+
? `Request timed out after ${this.timeoutMs} ms`
|
|
71
|
+
: `Network error: ${error instanceof Error ? error.message : String(error)}`,
|
|
72
|
+
});
|
|
73
|
+
if (attempt < this.maxRetries && !timedOut) {
|
|
74
|
+
await this.sleepFn(this.backoffMs(attempt));
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
throw lastError;
|
|
78
|
+
}
|
|
79
|
+
if (response.ok)
|
|
80
|
+
return response;
|
|
81
|
+
const errorBody = await response.text().catch(() => '');
|
|
82
|
+
lastError = new NbApiError({
|
|
83
|
+
status: response.status,
|
|
84
|
+
url,
|
|
85
|
+
body: errorBody,
|
|
86
|
+
message: extractApiMessage(errorBody),
|
|
87
|
+
});
|
|
88
|
+
if (RETRIABLE_STATUSES.has(response.status) && attempt < this.maxRetries) {
|
|
89
|
+
await this.sleepFn(this.backoffMs(attempt));
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
throw lastError;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
backoffMs(attempt) {
|
|
96
|
+
return 300 * 2 ** attempt + Math.floor(Math.random() * 100);
|
|
97
|
+
}
|
|
98
|
+
async parseJson(response) {
|
|
99
|
+
const text = await response.text();
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(text);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
throw new NbApiError({
|
|
105
|
+
status: response.status,
|
|
106
|
+
url: response.url ?? '',
|
|
107
|
+
body: text,
|
|
108
|
+
message: `Expected JSON response but got: ${redactKey(text.slice(0, 200))}`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** NextBillion error bodies vary: some use {status, msg}, others {code, message}. */
|
|
114
|
+
function extractApiMessage(bodyText) {
|
|
115
|
+
try {
|
|
116
|
+
const parsed = JSON.parse(bodyText);
|
|
117
|
+
const message = parsed.msg ?? parsed.message ?? parsed.error;
|
|
118
|
+
return typeof message === 'string' && message.length > 0 ? message : undefined;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return bodyText.length > 0 && bodyText.length <= 300 ? bodyText : undefined;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/nbclient/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Replace the API key value in any URL or message so it never leaks into tool results or logs. */
|
|
2
|
+
export declare function redactKey(text: string): string;
|
|
3
|
+
export declare class NbApiError extends Error {
|
|
4
|
+
readonly status: number | undefined;
|
|
5
|
+
readonly url: string;
|
|
6
|
+
readonly body: unknown;
|
|
7
|
+
constructor(options: {
|
|
8
|
+
status?: number;
|
|
9
|
+
url: string;
|
|
10
|
+
body?: unknown;
|
|
11
|
+
message?: string;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Replace the API key value in any URL or message so it never leaks into tool results or logs. */
|
|
2
|
+
export function redactKey(text) {
|
|
3
|
+
return text.replace(/([?&]key=)[^&\s'"]+/gi, '$1***');
|
|
4
|
+
}
|
|
5
|
+
const STATUS_HINTS = {
|
|
6
|
+
400: 'Input validation failed — a parameter is missing, malformed, or has an invalid value.',
|
|
7
|
+
401: 'API key is missing or invalid.',
|
|
8
|
+
403: 'API key is valid but has no access to this service or geographic region.',
|
|
9
|
+
404: 'Endpoint not found.',
|
|
10
|
+
413: 'Request URL or body is too large.',
|
|
11
|
+
414: 'Request URL is too long (max 8192 bytes) — use an encoded polyline or fewer points.',
|
|
12
|
+
422: 'The request is valid but no result could be produced (e.g. unroutable coordinates or no matching places).',
|
|
13
|
+
429: 'Rate limit or usage quota exceeded. Retry later or batch requests.',
|
|
14
|
+
500: 'NextBillion API internal error.',
|
|
15
|
+
};
|
|
16
|
+
export class NbApiError extends Error {
|
|
17
|
+
status;
|
|
18
|
+
url;
|
|
19
|
+
body;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
const hint = options.status !== undefined ? STATUS_HINTS[options.status] : undefined;
|
|
22
|
+
const parts = [
|
|
23
|
+
options.status !== undefined
|
|
24
|
+
? `NextBillion API error (HTTP ${options.status})`
|
|
25
|
+
: 'NextBillion API request failed',
|
|
26
|
+
options.message,
|
|
27
|
+
hint,
|
|
28
|
+
].filter(Boolean);
|
|
29
|
+
super(redactKey(parts.join(': ')));
|
|
30
|
+
this.name = 'NbApiError';
|
|
31
|
+
this.status = options.status;
|
|
32
|
+
this.url = redactKey(options.url);
|
|
33
|
+
this.body = options.body;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/nbclient/errors.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,IAAI,CAAC,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,YAAY,GAA2B;IAC3C,GAAG,EAAE,uFAAuF;IAC5F,GAAG,EAAE,gCAAgC;IACrC,GAAG,EAAE,0EAA0E;IAC/E,GAAG,EAAE,qBAAqB;IAC1B,GAAG,EAAE,mCAAmC;IACxC,GAAG,EAAE,qFAAqF;IAC1F,GAAG,EAAE,2GAA2G;IAChH,GAAG,EAAE,oEAAoE;IACzE,GAAG,EAAE,iCAAiC;CACvC,CAAC;AAEF,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,MAAM,CAAqB;IAC3B,GAAG,CAAS;IACZ,IAAI,CAAU;IAEvB,YAAY,OAA2E;QACrF,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrF,MAAM,KAAK,GAAG;YACZ,OAAO,CAAC,MAAM,KAAK,SAAS;gBAC1B,CAAC,CAAC,+BAA+B,OAAO,CAAC,MAAM,GAAG;gBAClD,CAAC,CAAC,gCAAgC;YACpC,OAAO,CAAC,OAAO;YACf,IAAI;SACL,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClB,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NbTool } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Every tool served by this MCP server, sorted by name. The order is deliberately
|
|
4
|
+
* deterministic: the 2026-07-28 revision requires list results not to vary per
|
|
5
|
+
* connection, and a stable order improves client-side prompt-cache hits.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ALL_TOOLS: ReadonlyArray<NbTool>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { autocomplete, autosuggest, geocodeForward, placeSearch } from './places/text-search.js';
|
|
2
|
+
import { geocodeBatch } from './places/geocode-batch.js';
|
|
3
|
+
import { geocodeReverse } from './places/geocode-reverse.js';
|
|
4
|
+
import { geocodeStructured } from './places/geocode-structured.js';
|
|
5
|
+
import { placeLookup } from './places/place-lookup.js';
|
|
6
|
+
import { postcodeLookup } from './places/postcode-lookup.js';
|
|
7
|
+
import { directions } from './routing/directions.js';
|
|
8
|
+
import { distanceMatrix } from './routing/distance-matrix.js';
|
|
9
|
+
import { isochrone } from './routing/isochrone.js';
|
|
10
|
+
import { searchAlongRoute } from './routing/search-along-route.js';
|
|
11
|
+
import { staticMapImage } from './maps/static-map-image.js';
|
|
12
|
+
import { staticRouteMap } from './maps/static-route-map.js';
|
|
13
|
+
/**
|
|
14
|
+
* Every tool served by this MCP server, sorted by name. The order is deliberately
|
|
15
|
+
* deterministic: the 2026-07-28 revision requires list results not to vary per
|
|
16
|
+
* connection, and a stable order improves client-side prompt-cache hits.
|
|
17
|
+
*/
|
|
18
|
+
export const ALL_TOOLS = [
|
|
19
|
+
autocomplete,
|
|
20
|
+
autosuggest,
|
|
21
|
+
directions,
|
|
22
|
+
distanceMatrix,
|
|
23
|
+
geocodeBatch,
|
|
24
|
+
geocodeForward,
|
|
25
|
+
geocodeReverse,
|
|
26
|
+
geocodeStructured,
|
|
27
|
+
isochrone,
|
|
28
|
+
placeLookup,
|
|
29
|
+
placeSearch,
|
|
30
|
+
postcodeLookup,
|
|
31
|
+
searchAlongRoute,
|
|
32
|
+
staticMapImage,
|
|
33
|
+
staticRouteMap,
|
|
34
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAA0B;IAC9C,YAAY;IACZ,WAAW;IACX,UAAU;IACV,cAAc;IACd,YAAY;IACZ,cAAc;IACd,cAAc;IACd,iBAAiB;IACjB,SAAS;IACT,WAAW;IACX,WAAW;IACX,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,cAAc;CACf,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { type NbTool } from '../types.js';
|
|
3
|
+
declare const Schema: z.ZodObject<{
|
|
4
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
5
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
style: z.ZodOptional<z.ZodString>;
|
|
7
|
+
format: z.ZodOptional<z.ZodEnum<{
|
|
8
|
+
jpg: "jpg";
|
|
9
|
+
png: "png";
|
|
10
|
+
webp: "webp";
|
|
11
|
+
}>>;
|
|
12
|
+
retina: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
center: z.ZodObject<{
|
|
14
|
+
latitude: z.ZodNumber;
|
|
15
|
+
longitude: z.ZodNumber;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
zoom: z.ZodNumber;
|
|
18
|
+
markers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
19
|
+
latitude: z.ZodNumber;
|
|
20
|
+
longitude: z.ZodNumber;
|
|
21
|
+
color: z.ZodOptional<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>>>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
export declare const staticMapImage: NbTool<typeof Schema>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { CoordinateSchema } from '../shared/geo.js';
|
|
3
|
+
import { READ_ONLY } from '../types.js';
|
|
4
|
+
import { fetchImageResult, markerParam, StaticImageShape, staticImagePath, } from './static-shared.js';
|
|
5
|
+
const Schema = z.object({
|
|
6
|
+
center: CoordinateSchema.describe('Center of the map view'),
|
|
7
|
+
zoom: z
|
|
8
|
+
.number()
|
|
9
|
+
.min(0)
|
|
10
|
+
.max(22)
|
|
11
|
+
.describe('Zoom level (0 = world, ~10 = city, ~15 = streets; fractional values allowed)'),
|
|
12
|
+
markers: z
|
|
13
|
+
.array(CoordinateSchema.extend({ color: z.string().optional() }))
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Markers to draw, each with optional color (e.g. "red", "#0000ff")'),
|
|
16
|
+
...StaticImageShape,
|
|
17
|
+
});
|
|
18
|
+
export const staticMapImage = {
|
|
19
|
+
name: 'static_map_image',
|
|
20
|
+
title: 'Static Map Image',
|
|
21
|
+
description: 'Render a static map image centered on a location, with optional markers. Returns the image ' +
|
|
22
|
+
'directly. To draw a route on a map use static_route_map instead.',
|
|
23
|
+
inputSchema: Schema,
|
|
24
|
+
annotations: READ_ONLY,
|
|
25
|
+
async run(args, nb) {
|
|
26
|
+
const position = `${args.center.latitude},${args.center.longitude},${args.zoom}`;
|
|
27
|
+
return fetchImageResult(nb, staticImagePath(position, args), { markers: args.markers?.length ? markerParam(args.markers) : undefined }, `Map centered at (${args.center.latitude}, ${args.center.longitude}), zoom ${args.zoom}` +
|
|
28
|
+
(args.markers?.length ? `, ${args.markers.length} marker(s).` : '.'), args);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=static-map-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-map-image.js","sourceRoot":"","sources":["../../../src/tools/maps/static-map-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAe,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAC3D,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,CAAC,8EAA8E,CAAC;IAC3F,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;SAChE,QAAQ,EAAE;SACV,QAAQ,CAAC,mEAAmE,CAAC;IAChF,GAAG,gBAAgB;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAA0B;IACnD,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,6FAA6F;QAC7F,kEAAkE;IACpE,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,SAAS;IACtB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE;QAChB,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACjF,OAAO,gBAAgB,CACrB,EAAE,EACF,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,EAC/B,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EACzE,oBAAoB,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC,SAAS,WAAW,IAAI,CAAC,IAAI,EAAE;YACtF,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EACtE,IAAI,CACL,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { type NbTool } from '../types.js';
|
|
3
|
+
declare const Schema: z.ZodObject<{
|
|
4
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
5
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
style: z.ZodOptional<z.ZodString>;
|
|
7
|
+
format: z.ZodOptional<z.ZodEnum<{
|
|
8
|
+
jpg: "jpg";
|
|
9
|
+
png: "png";
|
|
10
|
+
webp: "webp";
|
|
11
|
+
}>>;
|
|
12
|
+
retina: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
encoded_polyline: z.ZodOptional<z.ZodString>;
|
|
14
|
+
route_points: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
15
|
+
latitude: z.ZodNumber;
|
|
16
|
+
longitude: z.ZodNumber;
|
|
17
|
+
}, z.core.$strip>>>;
|
|
18
|
+
markers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
19
|
+
latitude: z.ZodNumber;
|
|
20
|
+
longitude: z.ZodNumber;
|
|
21
|
+
color: z.ZodOptional<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>>>;
|
|
23
|
+
stroke_color: z.ZodOptional<z.ZodString>;
|
|
24
|
+
stroke_width: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
padding: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export declare const staticRouteMap: NbTool<typeof Schema>;
|
|
28
|
+
export {};
|