@chrischall/mcp-utils 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/README.md +235 -0
- package/dist/auth/index.d.ts +223 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +267 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/config/index.d.ts +86 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +121 -0
- package/dist/config/index.js.map +1 -0
- package/dist/errors/index.d.ts +90 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +157 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/fetchproxy/index.d.ts +156 -0
- package/dist/fetchproxy/index.d.ts.map +1 -0
- package/dist/fetchproxy/index.js +197 -0
- package/dist/fetchproxy/index.js.map +1 -0
- package/dist/html/index.d.ts +142 -0
- package/dist/html/index.d.ts.map +1 -0
- package/dist/html/index.js +321 -0
- package/dist/html/index.js.map +1 -0
- package/dist/http/index.d.ts +202 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +341 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/response/index.d.ts +22 -0
- package/dist/response/index.d.ts.map +1 -0
- package/dist/response/index.js +61 -0
- package/dist/response/index.js.map +1 -0
- package/dist/server/index.d.ts +109 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +95 -0
- package/dist/server/index.js.map +1 -0
- package/dist/session/index.d.ts +233 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +404 -0
- package/dist/session/index.js.map +1 -0
- package/dist/test/index.d.ts +124 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +181 -0
- package/dist/test/index.js.map +1 -0
- package/dist/zod/index.d.ts +130 -0
- package/dist/zod/index.d.ts.map +1 -0
- package/dist/zod/index.js +184 -0
- package/dist/zod/index.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@chrischall/mcp-utils/test` — the in-memory vitest harness shared by every
|
|
3
|
+
* MCP in the fleet. Devtime-only: this subpath pulls test scaffolding and is
|
|
4
|
+
* never imported by runtime server code.
|
|
5
|
+
*
|
|
6
|
+
* It consolidates four copy-pasted pieces from ~19 sibling repos:
|
|
7
|
+
* - `createTestHarness` / `parseToolResult` — a connected `McpServer` + `Client`
|
|
8
|
+
* pair over `InMemoryTransport`, plus the trivial JSON-body extractor.
|
|
9
|
+
* - `versionSyncTest` — the release-please drift guard (`x-release-please-version`
|
|
10
|
+
* annotations vs `package.json#version`).
|
|
11
|
+
* - `mockFetchproxyBootstrap` / `setupClientMocks` — mock `@fetchproxy/bootstrap`
|
|
12
|
+
* at the module boundary and spy an API client's request methods.
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
15
|
+
import { join, relative } from 'node:path';
|
|
16
|
+
import { vi } from 'vitest';
|
|
17
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
18
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
19
|
+
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
|
|
20
|
+
/**
|
|
21
|
+
* Create a connected `McpServer` + `Client` pair wired over
|
|
22
|
+
* `InMemoryTransport`. The byte-identical helper every MCP's `tests/helpers.ts`
|
|
23
|
+
* defines — register your tools, then drive them through the real client RPC
|
|
24
|
+
* path (schema validation, content envelopes, isError, and all).
|
|
25
|
+
*/
|
|
26
|
+
export async function createTestHarness(registerFn) {
|
|
27
|
+
const server = new McpServer({ name: 'test', version: '0.0.0' });
|
|
28
|
+
await registerFn(server);
|
|
29
|
+
const client = new Client({ name: 'test-client', version: '0.0.0' });
|
|
30
|
+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
31
|
+
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
|
|
32
|
+
let closed = false;
|
|
33
|
+
return {
|
|
34
|
+
client,
|
|
35
|
+
server,
|
|
36
|
+
callTool: (name, args) => client.callTool({ name, arguments: args ?? {} }),
|
|
37
|
+
listTools: async () => {
|
|
38
|
+
const result = await client.listTools();
|
|
39
|
+
return result.tools.map((t) => ({ name: t.name }));
|
|
40
|
+
},
|
|
41
|
+
close: async () => {
|
|
42
|
+
if (closed)
|
|
43
|
+
return;
|
|
44
|
+
closed = true;
|
|
45
|
+
await client.close();
|
|
46
|
+
await server.close();
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parse the JSON body out of a tool's `CallToolResult`. Fleet tools return a
|
|
52
|
+
* single text block of `JSON.stringify(data, null, 2)`; this is the inverse.
|
|
53
|
+
* Throws a contextual error (rather than a bare `TypeError`/`SyntaxError`) when
|
|
54
|
+
* the result is empty, non-text, or not valid JSON — those are the test
|
|
55
|
+
* failures you actually want to read.
|
|
56
|
+
*/
|
|
57
|
+
export function parseToolResult(result) {
|
|
58
|
+
const block = result.content?.[0];
|
|
59
|
+
if (!block || block.type !== 'text' || typeof block.text !== 'string') {
|
|
60
|
+
throw new Error(`parseToolResult: result has no text content block (got ${block ? `type='${block.type}'` : 'empty content'})`);
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(block.text);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
67
|
+
throw new Error(`parseToolResult: text block is not valid JSON (${reason}): ${block.text}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const SEMVER_LITERAL = /['"]([0-9]+\.[0-9]+\.[0-9]+(?:-[A-Za-z0-9.]+)?)['"]/;
|
|
71
|
+
function walkTs(dir) {
|
|
72
|
+
const out = [];
|
|
73
|
+
for (const entry of readdirSync(dir)) {
|
|
74
|
+
const p = join(dir, entry);
|
|
75
|
+
if (statSync(p).isDirectory())
|
|
76
|
+
out.push(...walkTs(p));
|
|
77
|
+
else if (p.endsWith('.ts'))
|
|
78
|
+
out.push(p);
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The release-please drift guard. Walks `srcDir` for every line carrying an
|
|
84
|
+
* `x-release-please-version` annotation and asserts the version literal on that
|
|
85
|
+
* line matches `package.json#version`.
|
|
86
|
+
*
|
|
87
|
+
* Why this exists: a recurring footgun where a `VERSION` constant (the MCP's
|
|
88
|
+
* self-reported version + fetchproxy bridge identity) silently drifts from
|
|
89
|
+
* `package.json` because release-please's `extra-files` registration lacks the
|
|
90
|
+
* marker. resy-mcp v0.2.0 and opentable-mcp shipped this bug repeatedly.
|
|
91
|
+
*
|
|
92
|
+
* Returns the list of mismatch descriptions (`file:line → found (expected X)`).
|
|
93
|
+
* An empty array means in sync — callers assert `expect(result).toEqual([])`.
|
|
94
|
+
* Marker lines with no version literal (e.g. a docstring describing the
|
|
95
|
+
* convention) are intentionally skipped, so the test never trips on itself.
|
|
96
|
+
*/
|
|
97
|
+
export function versionSyncTest({ srcDir, pkgPath }) {
|
|
98
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
99
|
+
const root = join(srcDir, '..');
|
|
100
|
+
const mismatches = [];
|
|
101
|
+
for (const f of walkTs(srcDir)) {
|
|
102
|
+
const lines = readFileSync(f, 'utf8').split('\n');
|
|
103
|
+
lines.forEach((line, i) => {
|
|
104
|
+
if (!line.includes('x-release-please-version'))
|
|
105
|
+
return;
|
|
106
|
+
const match = line.match(SEMVER_LITERAL);
|
|
107
|
+
if (!match)
|
|
108
|
+
return;
|
|
109
|
+
const ver = match[1];
|
|
110
|
+
if (ver !== pkg.version) {
|
|
111
|
+
mismatches.push(`${relative(root, f)}:${i + 1} → ${ver} (expected ${pkg.version})`);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return mismatches;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Build a fully-shaped {@link BootstrapResult}, with empty maps as defaults and
|
|
119
|
+
* `overrides` shallow-merged on top. Keeps tests from re-declaring the four
|
|
120
|
+
* empty maps every time they only care about, say, `cookies`.
|
|
121
|
+
*/
|
|
122
|
+
export function makeBootstrapResult(overrides = {}) {
|
|
123
|
+
return {
|
|
124
|
+
cookies: {},
|
|
125
|
+
localStorage: {},
|
|
126
|
+
sessionStorage: {},
|
|
127
|
+
capturedHeaders: {},
|
|
128
|
+
...overrides,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Mock `@fetchproxy/bootstrap` at the module boundary so tests never open a
|
|
133
|
+
* real WebSocket to a browser bridge. Returns a spy that resolves a default
|
|
134
|
+
* {@link BootstrapResult} (overridable per call via `bootstrap.mockResolvedValue`).
|
|
135
|
+
*
|
|
136
|
+
* Usage:
|
|
137
|
+
* ```ts
|
|
138
|
+
* const fp = mockFetchproxyBootstrap({ cookies: { SID: 'x' } });
|
|
139
|
+
* vi.mock('@fetchproxy/bootstrap', fp.module);
|
|
140
|
+
* // ...import the SUT, then assert on fp.bootstrap
|
|
141
|
+
* ```
|
|
142
|
+
* Because `vi.mock` is hoisted, declare the mock handle and the `vi.mock` call
|
|
143
|
+
* before importing the system under test.
|
|
144
|
+
*/
|
|
145
|
+
export function mockFetchproxyBootstrap(defaultResult = {}) {
|
|
146
|
+
const base = makeBootstrapResult(defaultResult);
|
|
147
|
+
const bootstrap = vi.fn(async (..._args) => base);
|
|
148
|
+
return {
|
|
149
|
+
bootstrap,
|
|
150
|
+
module: () => ({ bootstrap: (...args) => bootstrap(...args) }),
|
|
151
|
+
reset: () => {
|
|
152
|
+
bootstrap.mockReset();
|
|
153
|
+
bootstrap.mockResolvedValue(base);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Spy on an API client's async request methods and (optionally) stub each one's
|
|
159
|
+
* resolved value. Mirrors the `vi.spyOn(client, 'request').mockResolvedValue(...)`
|
|
160
|
+
* boilerplate every tool-level test repeats.
|
|
161
|
+
*
|
|
162
|
+
* For each entry in `returns`: a spy is installed on `client[method]`. If the
|
|
163
|
+
* value is `undefined`, the spy passes through to the real implementation;
|
|
164
|
+
* otherwise it `mockResolvedValue`s the provided value. Remember to
|
|
165
|
+
* `vi.restoreAllMocks()` in `afterEach`.
|
|
166
|
+
*
|
|
167
|
+
* @returns A map of method name → installed spy, for call assertions.
|
|
168
|
+
*/
|
|
169
|
+
export function setupClientMocks(client, returns) {
|
|
170
|
+
const spies = {};
|
|
171
|
+
for (const method of Object.keys(returns)) {
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
173
|
+
const spy = vi.spyOn(client, method);
|
|
174
|
+
const value = returns[method];
|
|
175
|
+
if (value !== undefined)
|
|
176
|
+
spy.mockResolvedValue(value);
|
|
177
|
+
spies[method] = spy;
|
|
178
|
+
}
|
|
179
|
+
return spies;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `zod` — schema atoms, pagination, and tool-annotation helpers shared across
|
|
3
|
+
* the MCP fleet. Intentionally small: atoms + annotations, not a schema
|
|
4
|
+
* framework. Built on zod v4.
|
|
5
|
+
*
|
|
6
|
+
* The raw-shape style (`inputSchema: { foo: z.string() }`) used by
|
|
7
|
+
* `server.registerTool` is preserved — these atoms are plain `ZodType`s you
|
|
8
|
+
* drop straight into a shape object.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
/** A strictly positive integer (`> 0`). */
|
|
12
|
+
export declare const PositiveInt: z.ZodNumber;
|
|
13
|
+
/** A non-negative integer (`>= 0`). */
|
|
14
|
+
export declare const NonNegInt: z.ZodNumber;
|
|
15
|
+
/** A non-empty string (after no trimming — at least one character). */
|
|
16
|
+
export declare const NonEmptyString: z.ZodString;
|
|
17
|
+
/**
|
|
18
|
+
* An ISO calendar date, `YYYY-MM-DD`. Rejects impossible dates (e.g.
|
|
19
|
+
* `2026-13-01`) via zod v4's `z.iso.date()`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const IsoDate: z.ZodISODate;
|
|
22
|
+
/**
|
|
23
|
+
* A 24-hour wall-clock time `HH:MM` (no seconds, no offset). This is the
|
|
24
|
+
* fleet convention (resy notify/book, slot windows) — restaurant-local times
|
|
25
|
+
* carried as bare `HH:MM`, never parsed through `Date` so they aren't shifted
|
|
26
|
+
* by the server's timezone. Accepts `9:05` and `09:05`; rejects `24:00`,
|
|
27
|
+
* `19:60`, and anything with seconds.
|
|
28
|
+
*/
|
|
29
|
+
export declare const IsoTime: z.ZodString;
|
|
30
|
+
/**
|
|
31
|
+
* Optional portal-origin selector (e.g. `https://<vendor>.hbportal.co`).
|
|
32
|
+
* Disambiguates which signed-in session a tool routes through when more than
|
|
33
|
+
* one is active. Optional — when a single session is active it can be omitted.
|
|
34
|
+
* (honeybook / disk-session MCPs)
|
|
35
|
+
*/
|
|
36
|
+
export declare const schemaOrigin: z.ZodOptional<z.ZodString>;
|
|
37
|
+
/**
|
|
38
|
+
* The write-confirmation gate shared by mutating tools: without
|
|
39
|
+
* `confirm: true` the tool returns a preview instead of performing the action.
|
|
40
|
+
* (honeybook pay_invoice / sign_contract)
|
|
41
|
+
*/
|
|
42
|
+
export declare const schemaConfirm: z.ZodOptional<z.ZodBoolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Offset/limit pagination shape (raw, for spreading into an `inputSchema`).
|
|
45
|
+
* `offset` defaults to 0, `limit` is bounded `1..200` and defaults to 50 —
|
|
46
|
+
* the bounds standardized across the fleet's search tools.
|
|
47
|
+
*/
|
|
48
|
+
export declare const paginationSchema: {
|
|
49
|
+
readonly offset: z.ZodDefault<z.ZodNumber>;
|
|
50
|
+
readonly limit: z.ZodDefault<z.ZodNumber>;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* 1-based page pagination shape (`page_num` / `page_size`). `page_num`
|
|
54
|
+
* defaults to 1, `page_size` is bounded `1..200` and defaults to 50.
|
|
55
|
+
* Mirrors onehome-mcp's search pagination, normalized to 1-based.
|
|
56
|
+
*/
|
|
57
|
+
export declare const pageSchema: {
|
|
58
|
+
readonly page_num: z.ZodDefault<z.ZodNumber>;
|
|
59
|
+
readonly page_size: z.ZodDefault<z.ZodNumber>;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Convert a 1-based page + page size into a zero-based offset.
|
|
63
|
+
*
|
|
64
|
+
* Defensive against bad callers: page and size are floored, page is clamped to
|
|
65
|
+
* `>= 1` and size to `>= 0`, so the result is always a non-negative integer.
|
|
66
|
+
*
|
|
67
|
+
* @example calculateOffset(1, 50) // 0
|
|
68
|
+
* @example calculateOffset(3, 50) // 100
|
|
69
|
+
*/
|
|
70
|
+
export declare function calculateOffset(page: number, size: number): number;
|
|
71
|
+
/** The MCP tool-annotation block, as consumed by `server.registerTool`. */
|
|
72
|
+
export interface ToolAnnotations {
|
|
73
|
+
title: string;
|
|
74
|
+
readOnlyHint: boolean;
|
|
75
|
+
idempotentHint: boolean;
|
|
76
|
+
openWorldHint: boolean;
|
|
77
|
+
}
|
|
78
|
+
/** Options for {@link toolAnnotations}. */
|
|
79
|
+
export interface ToolAnnotationsInput {
|
|
80
|
+
/** Human-readable tool title (shown in clients). */
|
|
81
|
+
title: string;
|
|
82
|
+
/** Tool does not modify state. Default `true` (most fleet tools are reads). */
|
|
83
|
+
readOnly?: boolean;
|
|
84
|
+
/** Repeated identical calls have the same effect. Default `true`. */
|
|
85
|
+
idempotent?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Tool reaches an open/unbounded external world (the live web/API) rather
|
|
88
|
+
* than a closed local computation. Default `true`.
|
|
89
|
+
*/
|
|
90
|
+
openWorld?: boolean;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Build the `annotations` block repeated across ~15 tools per MCP. Defaults
|
|
94
|
+
* encode the fleet's common case (a read-only, idempotent, open-world fetch);
|
|
95
|
+
* mutating/local tools override the relevant hint.
|
|
96
|
+
*
|
|
97
|
+
* @example toolAnnotations({ title: 'Search properties' })
|
|
98
|
+
* // { title, readOnlyHint: true, idempotentHint: true, openWorldHint: true }
|
|
99
|
+
* @example toolAnnotations({ title: 'Book', readOnly: false, idempotent: false })
|
|
100
|
+
*/
|
|
101
|
+
export declare function toolAnnotations(opts: ToolAnnotationsInput): ToolAnnotations;
|
|
102
|
+
/**
|
|
103
|
+
* Extract bare `HH:MM` from an ISO-ish datetime such as
|
|
104
|
+
* `2026-05-01T19:00:00` or a wire time `19:00:00`. Deliberately avoids
|
|
105
|
+
* `new Date()` so times aren't shifted by the server's timezone (resy returns
|
|
106
|
+
* restaurant-local times with no offset). Returns `''` when no time is found.
|
|
107
|
+
*
|
|
108
|
+
* @example extractTime('2026-05-01T19:30:00') // '19:30'
|
|
109
|
+
* @example extractTime('19:30:00') // '19:30'
|
|
110
|
+
* @example extractTime(undefined) // ''
|
|
111
|
+
*/
|
|
112
|
+
export declare function extractTime(input: string | undefined | null): string;
|
|
113
|
+
/**
|
|
114
|
+
* Normalize a loose caller-supplied time to canonical 24-hour `HH:MM`.
|
|
115
|
+
*
|
|
116
|
+
* Accepts:
|
|
117
|
+
* - `HH:MM` / `H:MM` → zero-padded `HH:MM`
|
|
118
|
+
* - `HH:MM:SS` → seconds trimmed
|
|
119
|
+
* - `7pm`, `7:30 PM`, `12 am` → 12h clock converted (12am→00, 12pm→12)
|
|
120
|
+
*
|
|
121
|
+
* Returns `undefined` when the input can't be understood, so callers can fall
|
|
122
|
+
* through to a default rather than book at a garbage time.
|
|
123
|
+
*
|
|
124
|
+
* @example normalizeTime('7:30 PM') // '19:30'
|
|
125
|
+
* @example normalizeTime('9:5') // '09:05'
|
|
126
|
+
* @example normalizeTime('12am') // '00:00'
|
|
127
|
+
* @example normalizeTime('nope') // undefined
|
|
128
|
+
*/
|
|
129
|
+
export declare function normalizeTime(input: string | undefined | null): string | undefined;
|
|
130
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/zod/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,2CAA2C;AAC3C,eAAO,MAAM,WAAW,aAA8B,CAAC;AAEvD,uCAAuC;AACvC,eAAO,MAAM,SAAS,aAAiC,CAAC;AAExD,uEAAuE;AACvE,eAAO,MAAM,cAAc,aAAoB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,OAAO,cAAe,CAAC;AAEpC;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,aAEqD,CAAC;AAE1E;;;;;GAKG;AACH,eAAO,MAAM,YAAY,4BAKtB,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,aAAa,6BAGuD,CAAC;AAMlF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;CASnB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CASb,CAAC;AAEX;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlE;AAMD,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qEAAqE;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,oBAAoB,GAAG,eAAe,CAO3E;AAMD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAOpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAuBlF"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `zod` — schema atoms, pagination, and tool-annotation helpers shared across
|
|
3
|
+
* the MCP fleet. Intentionally small: atoms + annotations, not a schema
|
|
4
|
+
* framework. Built on zod v4.
|
|
5
|
+
*
|
|
6
|
+
* The raw-shape style (`inputSchema: { foo: z.string() }`) used by
|
|
7
|
+
* `server.registerTool` is preserved — these atoms are plain `ZodType`s you
|
|
8
|
+
* drop straight into a shape object.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Atoms
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/** A strictly positive integer (`> 0`). */
|
|
15
|
+
export const PositiveInt = z.number().int().positive();
|
|
16
|
+
/** A non-negative integer (`>= 0`). */
|
|
17
|
+
export const NonNegInt = z.number().int().nonnegative();
|
|
18
|
+
/** A non-empty string (after no trimming — at least one character). */
|
|
19
|
+
export const NonEmptyString = z.string().min(1);
|
|
20
|
+
/**
|
|
21
|
+
* An ISO calendar date, `YYYY-MM-DD`. Rejects impossible dates (e.g.
|
|
22
|
+
* `2026-13-01`) via zod v4's `z.iso.date()`.
|
|
23
|
+
*/
|
|
24
|
+
export const IsoDate = z.iso.date();
|
|
25
|
+
/**
|
|
26
|
+
* A 24-hour wall-clock time `HH:MM` (no seconds, no offset). This is the
|
|
27
|
+
* fleet convention (resy notify/book, slot windows) — restaurant-local times
|
|
28
|
+
* carried as bare `HH:MM`, never parsed through `Date` so they aren't shifted
|
|
29
|
+
* by the server's timezone. Accepts `9:05` and `09:05`; rejects `24:00`,
|
|
30
|
+
* `19:60`, and anything with seconds.
|
|
31
|
+
*/
|
|
32
|
+
export const IsoTime = z
|
|
33
|
+
.string()
|
|
34
|
+
.regex(/^([01]?\d|2[0-3]):[0-5]\d$/, 'must be HH:MM (24h), e.g. 19:30');
|
|
35
|
+
/**
|
|
36
|
+
* Optional portal-origin selector (e.g. `https://<vendor>.hbportal.co`).
|
|
37
|
+
* Disambiguates which signed-in session a tool routes through when more than
|
|
38
|
+
* one is active. Optional — when a single session is active it can be omitted.
|
|
39
|
+
* (honeybook / disk-session MCPs)
|
|
40
|
+
*/
|
|
41
|
+
export const schemaOrigin = z
|
|
42
|
+
.string()
|
|
43
|
+
.optional()
|
|
44
|
+
.describe('Portal origin (e.g. https://<vendor>.example.co) selecting which active session to use. Optional when only one session is active.');
|
|
45
|
+
/**
|
|
46
|
+
* The write-confirmation gate shared by mutating tools: without
|
|
47
|
+
* `confirm: true` the tool returns a preview instead of performing the action.
|
|
48
|
+
* (honeybook pay_invoice / sign_contract)
|
|
49
|
+
*/
|
|
50
|
+
export const schemaConfirm = z
|
|
51
|
+
.boolean()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Must be true to proceed. Without this, the tool returns a preview.');
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Pagination
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/**
|
|
58
|
+
* Offset/limit pagination shape (raw, for spreading into an `inputSchema`).
|
|
59
|
+
* `offset` defaults to 0, `limit` is bounded `1..200` and defaults to 50 —
|
|
60
|
+
* the bounds standardized across the fleet's search tools.
|
|
61
|
+
*/
|
|
62
|
+
export const paginationSchema = {
|
|
63
|
+
offset: NonNegInt.default(0).describe('Number of items to skip (0-based).'),
|
|
64
|
+
limit: z
|
|
65
|
+
.number()
|
|
66
|
+
.int()
|
|
67
|
+
.min(1)
|
|
68
|
+
.max(200)
|
|
69
|
+
.default(50)
|
|
70
|
+
.describe('Maximum number of items to return (1-200).'),
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* 1-based page pagination shape (`page_num` / `page_size`). `page_num`
|
|
74
|
+
* defaults to 1, `page_size` is bounded `1..200` and defaults to 50.
|
|
75
|
+
* Mirrors onehome-mcp's search pagination, normalized to 1-based.
|
|
76
|
+
*/
|
|
77
|
+
export const pageSchema = {
|
|
78
|
+
page_num: PositiveInt.default(1).describe('1-based page number.'),
|
|
79
|
+
page_size: z
|
|
80
|
+
.number()
|
|
81
|
+
.int()
|
|
82
|
+
.min(1)
|
|
83
|
+
.max(200)
|
|
84
|
+
.default(50)
|
|
85
|
+
.describe('Number of items per page (1-200).'),
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Convert a 1-based page + page size into a zero-based offset.
|
|
89
|
+
*
|
|
90
|
+
* Defensive against bad callers: page and size are floored, page is clamped to
|
|
91
|
+
* `>= 1` and size to `>= 0`, so the result is always a non-negative integer.
|
|
92
|
+
*
|
|
93
|
+
* @example calculateOffset(1, 50) // 0
|
|
94
|
+
* @example calculateOffset(3, 50) // 100
|
|
95
|
+
*/
|
|
96
|
+
export function calculateOffset(page, size) {
|
|
97
|
+
const p = Math.max(1, Math.floor(page));
|
|
98
|
+
const s = Math.max(0, Math.floor(size));
|
|
99
|
+
return (p - 1) * s;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Build the `annotations` block repeated across ~15 tools per MCP. Defaults
|
|
103
|
+
* encode the fleet's common case (a read-only, idempotent, open-world fetch);
|
|
104
|
+
* mutating/local tools override the relevant hint.
|
|
105
|
+
*
|
|
106
|
+
* @example toolAnnotations({ title: 'Search properties' })
|
|
107
|
+
* // { title, readOnlyHint: true, idempotentHint: true, openWorldHint: true }
|
|
108
|
+
* @example toolAnnotations({ title: 'Book', readOnly: false, idempotent: false })
|
|
109
|
+
*/
|
|
110
|
+
export function toolAnnotations(opts) {
|
|
111
|
+
return {
|
|
112
|
+
title: opts.title,
|
|
113
|
+
readOnlyHint: opts.readOnly ?? true,
|
|
114
|
+
idempotentHint: opts.idempotent ?? true,
|
|
115
|
+
openWorldHint: opts.openWorld ?? true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Time normalization (resy)
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
/**
|
|
122
|
+
* Extract bare `HH:MM` from an ISO-ish datetime such as
|
|
123
|
+
* `2026-05-01T19:00:00` or a wire time `19:00:00`. Deliberately avoids
|
|
124
|
+
* `new Date()` so times aren't shifted by the server's timezone (resy returns
|
|
125
|
+
* restaurant-local times with no offset). Returns `''` when no time is found.
|
|
126
|
+
*
|
|
127
|
+
* @example extractTime('2026-05-01T19:30:00') // '19:30'
|
|
128
|
+
* @example extractTime('19:30:00') // '19:30'
|
|
129
|
+
* @example extractTime(undefined) // ''
|
|
130
|
+
*/
|
|
131
|
+
export function extractTime(input) {
|
|
132
|
+
if (!input)
|
|
133
|
+
return '';
|
|
134
|
+
// Prefer the time component after a `T`; fall back to a leading HH:MM[:SS].
|
|
135
|
+
const afterT = /T(\d{2}):(\d{2})/.exec(input);
|
|
136
|
+
if (afterT)
|
|
137
|
+
return `${afterT[1]}:${afterT[2]}`;
|
|
138
|
+
const leading = /^(\d{2}):(\d{2})/.exec(input);
|
|
139
|
+
return leading ? `${leading[1]}:${leading[2]}` : '';
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Normalize a loose caller-supplied time to canonical 24-hour `HH:MM`.
|
|
143
|
+
*
|
|
144
|
+
* Accepts:
|
|
145
|
+
* - `HH:MM` / `H:MM` → zero-padded `HH:MM`
|
|
146
|
+
* - `HH:MM:SS` → seconds trimmed
|
|
147
|
+
* - `7pm`, `7:30 PM`, `12 am` → 12h clock converted (12am→00, 12pm→12)
|
|
148
|
+
*
|
|
149
|
+
* Returns `undefined` when the input can't be understood, so callers can fall
|
|
150
|
+
* through to a default rather than book at a garbage time.
|
|
151
|
+
*
|
|
152
|
+
* @example normalizeTime('7:30 PM') // '19:30'
|
|
153
|
+
* @example normalizeTime('9:5') // '09:05'
|
|
154
|
+
* @example normalizeTime('12am') // '00:00'
|
|
155
|
+
* @example normalizeTime('nope') // undefined
|
|
156
|
+
*/
|
|
157
|
+
export function normalizeTime(input) {
|
|
158
|
+
if (!input)
|
|
159
|
+
return undefined;
|
|
160
|
+
const s = input.trim().toLowerCase();
|
|
161
|
+
if (!s)
|
|
162
|
+
return undefined;
|
|
163
|
+
const m = /^(\d{1,2})(?::(\d{1,2}))?(?::\d{1,2})?\s*(am|pm)?$/.exec(s);
|
|
164
|
+
if (!m)
|
|
165
|
+
return undefined;
|
|
166
|
+
let hour = Number(m[1]);
|
|
167
|
+
const minute = m[2] === undefined ? 0 : Number(m[2]);
|
|
168
|
+
const meridiem = m[3];
|
|
169
|
+
if (minute > 59)
|
|
170
|
+
return undefined;
|
|
171
|
+
if (meridiem) {
|
|
172
|
+
if (hour < 1 || hour > 12)
|
|
173
|
+
return undefined;
|
|
174
|
+
if (meridiem === 'am')
|
|
175
|
+
hour = hour === 12 ? 0 : hour;
|
|
176
|
+
else
|
|
177
|
+
hour = hour === 12 ? 12 : hour + 12;
|
|
178
|
+
}
|
|
179
|
+
else if (hour > 23) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
return `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/zod/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chrischall/mcp-utils",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared scaffolding for the chrischall MCP fleet — server bootstrap, tool-result formatting, helpful errors, hardened env/config, a bearer API-client kit, zod atoms, session registries, a fetchproxy transport adapter, auth resolver skeletons, an in-memory test harness, and opt-in HTML helpers. The generic MCP glue hoisted out of ~19 sibling servers.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/chrischall/mcp-utils.git"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./test": {
|
|
20
|
+
"import": "./dist/test/index.js",
|
|
21
|
+
"types": "./dist/test/index.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./fetchproxy": {
|
|
24
|
+
"import": "./dist/fetchproxy/index.js",
|
|
25
|
+
"types": "./dist/fetchproxy/index.d.ts"
|
|
26
|
+
},
|
|
27
|
+
"./session": {
|
|
28
|
+
"import": "./dist/session/index.js",
|
|
29
|
+
"types": "./dist/session/index.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./html": {
|
|
32
|
+
"import": "./dist/html/index.js",
|
|
33
|
+
"types": "./dist/html/index.d.ts"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"provenance": true
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc -b",
|
|
45
|
+
"typecheck": "tsc -b --noEmit false",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
51
|
+
"zod": "^4.4.0",
|
|
52
|
+
"@fetchproxy/server": "*",
|
|
53
|
+
"node-html-parser": "*",
|
|
54
|
+
"vitest": "*"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"@fetchproxy/server": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"node-html-parser": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"vitest": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@fetchproxy/server": "^0.11.0",
|
|
69
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
70
|
+
"@types/node": "^24.0.0",
|
|
71
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
72
|
+
"node-html-parser": "^7.1.0",
|
|
73
|
+
"typescript": "^5.6.0",
|
|
74
|
+
"vitest": "^4.1.0",
|
|
75
|
+
"zod": "^4.4.0"
|
|
76
|
+
}
|
|
77
|
+
}
|