feat: add a tool catalog and local MCP server

Define tools that answer questions from the app's data once, independent
of the surface that exposes them. A tool declares its arguments and the
services it reads; applications compose tools with their own services and
optional call interceptors. Queries reuse the layers' portable source
factories, so they run wherever an application routes /api requests.

The first queries are get_earthquakes, get_active_fires and
get_recent_launches, with a shared area argument (place name, bounding
box, or point and radius) and capped lists.

gods-eye-view/tools/mcp adapts a catalog to the Model Context Protocol
with a small JSON-RPC handler and a stateless HTTP transport, adding no
dependencies. npm run mcp serves Core's tools over stdio to local clients
such as Claude Code, reading from a running app. Both exports are
portable and checked by check:boundaries; the app does not import them.
This commit is contained in:
Sameh Khamis committed 2026-10-01 11:51:59 -07:00
1 parent e7707d9a0f
commit c3dfa8e853
26 files changed
+1886 -3

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
/** Result sizing shared by tools that return lists. */
export const DEFAULT_LIMIT = 25;
export const MAX_LIMIT = 200;
/** JSON Schema for the `limit` argument. */
export const LIMIT_SCHEMA = Object.freeze({
type: 'integer',
minimum: 1,
maximum: MAX_LIMIT,
description: `Most rows to return (default ${DEFAULT_LIMIT}, at most ${MAX_LIMIT}).`,
});
/** Keep the first `limit` rows and report how many matched in total. */
export function capRows(rows, limit = DEFAULT_LIMIT) {
const kept = rows.slice(0, Math.min(limit, MAX_LIMIT));
return {
total: rows.length,
returned: kept.length,
truncated: kept.length < rows.length,
rows: kept,
};
}
/** Format an epoch millisecond time as ISO 8601, or null. */
export function isoTime(ms) {
return Number.isFinite(ms) ? new Date(ms).toISOString() : null;
}
/** "1 earthquake", "3 earthquakes". */
export function countNoun(count, singular, plural = `${singular}s`) {
return `${count} ${count === 1 ? singular : plural}`;
}