@cyanheads/wsdot-mcp-server 0.2.1 → 0.2.2
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/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/README.md +6 -2
- package/changelog/0.2.x/0.2.2.md +15 -0
- package/dist/mcp-server/tools/definitions/get-terminal-space.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/get-terminal-space.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-terminal-space.tool.js +61 -7
- package/dist/mcp-server/tools/definitions/get-terminal-space.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-toll-rates.tool.d.ts +6 -1
- package/dist/mcp-server/tools/definitions/get-toll-rates.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-toll-rates.tool.js +49 -9
- package/dist/mcp-server/tools/definitions/get-toll-rates.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-travel-times.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/get-travel-times.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-travel-times.tool.js +51 -7
- package/dist/mcp-server/tools/definitions/get-travel-times.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-alerts.tool.js +51 -7
- package/dist/mcp-server/tools/definitions/search-alerts.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-cameras.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-cameras.tool.js +7 -2
- package/dist/mcp-server/tools/definitions/search-cameras.tool.js.map +1 -1
- package/dist/services/traffic/stable-order.d.ts +20 -0
- package/dist/services/traffic/stable-order.d.ts.map +1 -0
- package/dist/services/traffic/stable-order.js +29 -0
- package/dist/services/traffic/stable-order.js.map +1 -0
- package/package.json +1 -1
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/wsdot-mcp-server
|
|
4
|
-
**Version:** 0.2.
|
|
4
|
+
**Version:** 0.2.2
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.11.0`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
|
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/wsdot-mcp-server
|
|
4
|
-
**Version:** 0.2.
|
|
4
|
+
**Version:** 0.2.2
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.11.0`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/wsdot-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/wsdot-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -61,6 +61,7 @@ Active WA highway alerts — incidents, construction, closures, restrictions.
|
|
|
61
61
|
- Filter by milepost range to scope to a corridor — an alert matches when its extent overlaps the range, so a closure that spans the boundary is returned
|
|
62
62
|
- Omit all filters to return all current statewide alerts
|
|
63
63
|
- Descriptions are plain text — upstream authors them with markup, and a link is rendered inline as `link text (url)` so the destination survives
|
|
64
|
+
- Results are ordered by `alertId` and paged (default 50, max 500) — pass `offset`/`limit` to page through the full statewide set; the notice reports the next offset. Upstream returns the same alert set in more than one row order, so the ordering is imposed here to keep a given offset reproducible
|
|
64
65
|
|
|
65
66
|
---
|
|
66
67
|
|
|
@@ -72,6 +73,7 @@ Current vs. average travel times for named WA highway corridors.
|
|
|
72
73
|
- Filter by route (`"I-5"`, `"5"`, `"SR 520"`) to get every corridor measured on it, or by any text to match corridor names (`"Everett"`)
|
|
73
74
|
- When current time exceeds average, the corridor is congested; the delta is the delay
|
|
74
75
|
- Reversible express-lane corridors report no travel time while closed in the queried direction — those figures are omitted rather than reported as zero minutes
|
|
76
|
+
- Results are paged (default 50, max 500) — pass `offset`/`limit` to page through the full statewide set; the notice reports the next offset
|
|
75
77
|
|
|
76
78
|
---
|
|
77
79
|
|
|
@@ -81,6 +83,7 @@ Current dynamic toll rates for WA tolled facilities.
|
|
|
81
83
|
|
|
82
84
|
- SR 99 (WSDOT Tunnel), SR 520 Bridge, I-405 Express Lanes, I-90 Two-Way Express Lanes, SR 167 HOT Lanes
|
|
83
85
|
- Rates are time-banded and change dynamically based on traffic conditions
|
|
86
|
+
- Results are paged (default 50, max 500) — pass `offset`/`limit` to page through the full statewide set; the notice reports the next offset
|
|
84
87
|
|
|
85
88
|
---
|
|
86
89
|
|
|
@@ -101,7 +104,7 @@ WSDOT highway camera metadata and image URLs.
|
|
|
101
104
|
- Filter by state route (`"I-90"`, `"90"`, `"SR 520"`, or `"520"` all work), WSDOT region, or milepost range
|
|
102
105
|
- Camera road names carry a route-type prefix, so `"SR 26"` excludes US 26 and `"US 97"` excludes US 97A; a bare `"26"` returns both
|
|
103
106
|
- Returns metadata and image URLs — camera images are copyright WSDOT, not fetched as bytes
|
|
104
|
-
- Results are paged (default 50, max 500) — pass `offset`/`limit` to page through the full statewide set; the notice reports the next offset
|
|
107
|
+
- Results are ordered by `cameraId` and paged (default 50, max 500) — pass `offset`/`limit` to page through the full statewide set; the notice reports the next offset. Upstream returns the same camera set in more than one row order, so the ordering is imposed here to keep a given offset reproducible
|
|
105
108
|
|
|
106
109
|
---
|
|
107
110
|
|
|
@@ -153,6 +156,7 @@ Real-time vehicle space availability at WSF terminals for upcoming sailings.
|
|
|
153
156
|
- `arrivingTerminalIds` lists the terminals a sailing serves and chains straight into `wsdot_get_ferry_schedule`; `itineraryLabel` is a display string that may name several stops, not a single destination
|
|
154
157
|
- Filter to a specific terminal by ID (from `wsdot_get_ferry_terminals`)
|
|
155
158
|
- Use for "will I make the ferry?" or "how full is the next sailing?" queries
|
|
159
|
+
- Results are paged by terminal (default 5, max 20) — `offset`/`limit` select whole terminals and `totalCount` counts matching terminals, not sailings; every sailing of a returned terminal is included, so page size varies with how many departures each terminal carries
|
|
156
160
|
|
|
157
161
|
---
|
|
158
162
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "`offset`/`limit` paging added to `wsdot_search_alerts`, `wsdot_get_travel_times`, `wsdot_get_toll_rates`, and `wsdot_get_terminal_space` (#24); `wsdot_search_alerts` and `wsdot_search_cameras` now impose a deterministic row order before paging, which changes their default result order."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.2.2 — 2026-07-30
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`offset`/`limit` paging on four more tools.** `wsdot_search_alerts`, `wsdot_get_travel_times`, and `wsdot_get_toll_rates` page at the row level (default 50, max 500); `wsdot_get_terminal_space` pages at the terminal level (default 5, max 20), since each terminal carries every sailing it reports. All four follow the contract `wsdot_search_cameras` already used: paging happens in the handler after every filter, `enrichment.totalCount` stays the full filtered count, and `nextOffset`/`hasMore`/a page-window notice reach both `structuredContent` and `content[]` ([#24](https://github.com/cyanheads/wsdot-mcp-server/issues/24)).
|
|
12
|
+
|
|
13
|
+
## Fixed
|
|
14
|
+
|
|
15
|
+
- **`wsdot_search_alerts` and `wsdot_search_cameras` now page in a stable order.** Live verification found both feeds serve the same row set in more than one order across repeated fetches — since every page is a separate upstream fetch, an unordered offset silently skipped and duplicated rows across a walk. Both tools now sort by `alertId`/`cameraId` (`src/services/traffic/stable-order.ts`, rows without an id sorting last) before slicing, making a given offset reproducible. **This changes the default result order of both tools for every existing caller.**
|
|
@@ -6,6 +6,8 @@ import { z } from '@cyanheads/mcp-ts-core';
|
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
export declare const getTerminalSpace: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
8
|
departingTerminalId: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
9
11
|
}, z.core.$strip>, z.ZodObject<{
|
|
10
12
|
terminals: z.ZodArray<z.ZodObject<{
|
|
11
13
|
terminalId: z.ZodOptional<z.ZodNumber>;
|
|
@@ -38,6 +40,8 @@ export declare const getTerminalSpace: import("@cyanheads/mcp-ts-core").ToolDefi
|
|
|
38
40
|
readonly recovery: "Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.";
|
|
39
41
|
}], {
|
|
40
42
|
readonly totalCount: z.ZodNumber;
|
|
43
|
+
readonly nextOffset: z.ZodNullable<z.ZodNumber>;
|
|
44
|
+
readonly hasMore: z.ZodBoolean;
|
|
41
45
|
readonly terminalFilter: z.ZodOptional<z.ZodNumber>;
|
|
42
46
|
readonly notice: z.ZodOptional<z.ZodString>;
|
|
43
47
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-terminal-space.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-terminal-space.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"get-terminal-space.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-terminal-space.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAWjE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsP3B,CAAC"}
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { getFerryApiService } from '../../../services/ferry/ferry-service.js';
|
|
8
|
+
/**
|
|
9
|
+
* Paging unit is the terminal, not the sailing: offset/limit select whole terminals and each
|
|
10
|
+
* one arrives with every upcoming sailing it reports. WSF operates roughly 20 terminals, so
|
|
11
|
+
* MAX_LIMIT reaches the entire set in one call while the default bounds a browse of all of them.
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_LIMIT = 5;
|
|
14
|
+
const MAX_LIMIT = 20;
|
|
8
15
|
export const getTerminalSpace = tool('wsdot_get_terminal_space', {
|
|
9
16
|
title: 'Get Terminal Space',
|
|
10
17
|
description: 'Returns real-time drive-up and reservable vehicle space available at WSF terminals for upcoming sailings. ' +
|
|
@@ -12,13 +19,29 @@ export const getTerminalSpace = tool('wsdot_get_terminal_space', {
|
|
|
12
19
|
'Optionally filter to a specific terminal by ID (use wsdot_get_ferry_terminals for the ID). ' +
|
|
13
20
|
'driveUpSpaceCount is the key field — zero means the drive-up lane is full. ' +
|
|
14
21
|
'Destinations are arrivingTerminalIds, not the itineraryLabel string: a sailing can serve ' +
|
|
15
|
-
'several terminals, and those IDs are what wsdot_get_ferry_schedule accepts.'
|
|
22
|
+
'several terminals, and those IDs are what wsdot_get_ferry_schedule accepts. ' +
|
|
23
|
+
`Results are paged by terminal (default ${DEFAULT_LIMIT}, max ${MAX_LIMIT}): offset/limit select whole terminals ` +
|
|
24
|
+
'and totalCount counts matching terminals, not sailings — every sailing of a returned terminal is included, ' +
|
|
25
|
+
'so page size varies with how many departures each terminal carries.',
|
|
16
26
|
annotations: { readOnlyHint: true },
|
|
17
27
|
input: z.object({
|
|
18
28
|
departingTerminalId: z
|
|
19
29
|
.number()
|
|
20
30
|
.optional()
|
|
21
31
|
.describe('Filter to a specific terminal by numeric ID. Omit to return all terminals.'),
|
|
32
|
+
offset: z
|
|
33
|
+
.number()
|
|
34
|
+
.int()
|
|
35
|
+
.min(0)
|
|
36
|
+
.optional()
|
|
37
|
+
.describe('Zero-based index of the first terminal to return, for paging. Defaults to 0.'),
|
|
38
|
+
limit: z
|
|
39
|
+
.number()
|
|
40
|
+
.int()
|
|
41
|
+
.min(1)
|
|
42
|
+
.max(MAX_LIMIT)
|
|
43
|
+
.optional()
|
|
44
|
+
.describe(`Maximum terminals to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}. Counts terminals, not sailings.`),
|
|
22
45
|
}),
|
|
23
46
|
output: z.object({
|
|
24
47
|
terminals: z
|
|
@@ -78,7 +101,14 @@ export const getTerminalSpace = tool('wsdot_get_terminal_space', {
|
|
|
78
101
|
.describe('Terminal space availability by terminal.'),
|
|
79
102
|
}),
|
|
80
103
|
enrichment: {
|
|
81
|
-
totalCount: z
|
|
104
|
+
totalCount: z
|
|
105
|
+
.number()
|
|
106
|
+
.describe('Total terminals matching the filter across all pages (not just this page). Counts terminals, not sailings.'),
|
|
107
|
+
nextOffset: z
|
|
108
|
+
.number()
|
|
109
|
+
.nullable()
|
|
110
|
+
.describe('Offset to pass to retrieve the next page, or null when this is the last page.'),
|
|
111
|
+
hasMore: z.boolean().describe('True when more terminals remain beyond the current page.'),
|
|
82
112
|
terminalFilter: z
|
|
83
113
|
.number()
|
|
84
114
|
.optional()
|
|
@@ -86,7 +116,7 @@ export const getTerminalSpace = tool('wsdot_get_terminal_space', {
|
|
|
86
116
|
notice: z
|
|
87
117
|
.string()
|
|
88
118
|
.optional()
|
|
89
|
-
.describe('
|
|
119
|
+
.describe('Informational note about the page window, or guidance when no terminal space data is available, the filter matched nothing, or the offset ran past the end.'),
|
|
90
120
|
},
|
|
91
121
|
errors: [
|
|
92
122
|
{
|
|
@@ -109,17 +139,41 @@ export const getTerminalSpace = tool('wsdot_get_terminal_space', {
|
|
|
109
139
|
const filtered = input.departingTerminalId != null
|
|
110
140
|
? all.filter((t) => t.terminalId === input.departingTerminalId)
|
|
111
141
|
: all;
|
|
112
|
-
|
|
142
|
+
// Page the filtered set at the terminal level so structuredContent and content[] carry the
|
|
143
|
+
// identical page and no terminal's sailings are split across two calls (the service stays
|
|
144
|
+
// filter-only; paging is a tool-handler concern). totalCount stays the full match count.
|
|
145
|
+
const totalCount = filtered.length;
|
|
146
|
+
const offset = input.offset ?? 0;
|
|
147
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
148
|
+
const terminals = filtered.slice(offset, offset + limit);
|
|
149
|
+
const hasMore = offset + terminals.length < totalCount;
|
|
150
|
+
const nextOffset = hasMore ? offset + terminals.length : null;
|
|
151
|
+
ctx.log.info('Terminal space fetched', {
|
|
152
|
+
total: all.length,
|
|
153
|
+
totalCount,
|
|
154
|
+
offset,
|
|
155
|
+
limit,
|
|
156
|
+
returned: terminals.length,
|
|
157
|
+
});
|
|
113
158
|
ctx.enrich({
|
|
114
|
-
totalCount
|
|
159
|
+
totalCount,
|
|
160
|
+
nextOffset,
|
|
161
|
+
hasMore,
|
|
115
162
|
...(input.departingTerminalId != null && { terminalFilter: input.departingTerminalId }),
|
|
116
163
|
});
|
|
117
|
-
if (
|
|
164
|
+
if (totalCount === 0) {
|
|
118
165
|
ctx.enrich.notice(input.departingTerminalId != null
|
|
119
166
|
? `No terminal space data found for terminal ID ${input.departingTerminalId}. Use wsdot_get_ferry_terminals to verify valid terminal IDs.`
|
|
120
167
|
: 'No terminal space data available. The WSF API may be temporarily unavailable — retry in 30 seconds.');
|
|
121
168
|
}
|
|
122
|
-
|
|
169
|
+
else if (terminals.length === 0) {
|
|
170
|
+
ctx.enrich.notice(`Offset ${offset} is past the end of ${totalCount} matching terminals. Use an offset between 0 and ${totalCount - 1}.`);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
const window = `Showing terminals ${offset + 1}–${offset + terminals.length} of ${totalCount}, each with all of its upcoming sailings.`;
|
|
174
|
+
ctx.enrich.notice(hasMore ? `${window} Pass offset=${nextOffset} for the next page.` : window);
|
|
175
|
+
}
|
|
176
|
+
return { terminals };
|
|
123
177
|
},
|
|
124
178
|
format: (result) => {
|
|
125
179
|
if (result.terminals.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-terminal-space.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-terminal-space.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,0BAA0B,EAAE;IAC/D,KAAK,EAAE,oBAAoB;IAC3B,WAAW,EACT,4GAA4G;QAC5G,iFAAiF;QACjF,6FAA6F;QAC7F,6EAA6E;QAC7E,2FAA2F;QAC3F,
|
|
1
|
+
{"version":3,"file":"get-terminal-space.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-terminal-space.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
export declare const getTollRates: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
7
|
+
export declare const getTollRates: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
8
11
|
rates: z.ZodArray<z.ZodObject<{
|
|
9
12
|
tripName: z.ZodOptional<z.ZodString>;
|
|
10
13
|
stateRoute: z.ZodOptional<z.ZodString>;
|
|
@@ -35,6 +38,8 @@ export declare const getTollRates: import("@cyanheads/mcp-ts-core").ToolDefiniti
|
|
|
35
38
|
readonly recovery: "Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.";
|
|
36
39
|
}], {
|
|
37
40
|
readonly totalCount: z.ZodNumber;
|
|
41
|
+
readonly nextOffset: z.ZodNullable<z.ZodNumber>;
|
|
42
|
+
readonly hasMore: z.ZodBoolean;
|
|
38
43
|
readonly notice: z.ZodOptional<z.ZodString>;
|
|
39
44
|
}>;
|
|
40
45
|
//# sourceMappingURL=get-toll-rates.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-toll-rates.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-toll-rates.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"get-toll-rates.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-toll-rates.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAMjE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+JvB,CAAC"}
|
|
@@ -5,13 +5,30 @@
|
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { getTrafficApiService } from '../../../services/traffic/traffic-service.js';
|
|
8
|
+
const DEFAULT_LIMIT = 50;
|
|
9
|
+
const MAX_LIMIT = 500;
|
|
8
10
|
export const getTollRates = tool('wsdot_get_toll_rates', {
|
|
9
11
|
title: 'Get Toll Rates',
|
|
10
12
|
description: 'Returns current dynamic toll rates for WA express lanes and tolled facilities: SR 99 (WSDOT Tunnel), ' +
|
|
11
13
|
'SR 520 Bridge, I-405 Express Lanes, I-90 Two-Way Express Lanes, and SR 167 HOT Lanes. ' +
|
|
12
|
-
'Rates are time-banded and change dynamically based on traffic conditions.'
|
|
14
|
+
'Rates are time-banded and change dynamically based on traffic conditions. ' +
|
|
15
|
+
'Results are paged — pass offset/limit to page through the full set (the notice reports the next offset).',
|
|
13
16
|
annotations: { readOnlyHint: true },
|
|
14
|
-
input: z.object({
|
|
17
|
+
input: z.object({
|
|
18
|
+
offset: z
|
|
19
|
+
.number()
|
|
20
|
+
.int()
|
|
21
|
+
.min(0)
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Zero-based index of the first toll rate to return, for paging. Defaults to 0.'),
|
|
24
|
+
limit: z
|
|
25
|
+
.number()
|
|
26
|
+
.int()
|
|
27
|
+
.min(1)
|
|
28
|
+
.max(MAX_LIMIT)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe(`Maximum toll rates to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}.`),
|
|
31
|
+
}),
|
|
15
32
|
output: z.object({
|
|
16
33
|
rates: z
|
|
17
34
|
.array(z
|
|
@@ -44,11 +61,18 @@ export const getTollRates = tool('wsdot_get_toll_rates', {
|
|
|
44
61
|
.describe('Current toll rates for all active tolled facilities.'),
|
|
45
62
|
}),
|
|
46
63
|
enrichment: {
|
|
47
|
-
totalCount: z
|
|
64
|
+
totalCount: z
|
|
65
|
+
.number()
|
|
66
|
+
.describe('Total toll rate entries across all pages (not just this page).'),
|
|
67
|
+
nextOffset: z
|
|
68
|
+
.number()
|
|
69
|
+
.nullable()
|
|
70
|
+
.describe('Offset to pass to retrieve the next page, or null when this is the last page.'),
|
|
71
|
+
hasMore: z.boolean().describe('True when more toll rates remain beyond the current page.'),
|
|
48
72
|
notice: z
|
|
49
73
|
.string()
|
|
50
74
|
.optional()
|
|
51
|
-
.describe('
|
|
75
|
+
.describe('Informational note about the page window, or guidance when no toll rate data is available or the offset ran past the end.'),
|
|
52
76
|
},
|
|
53
77
|
errors: [
|
|
54
78
|
{
|
|
@@ -66,13 +90,29 @@ export const getTollRates = tool('wsdot_get_toll_rates', {
|
|
|
66
90
|
recovery: 'Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.',
|
|
67
91
|
},
|
|
68
92
|
],
|
|
69
|
-
async handler(
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
93
|
+
async handler(input, ctx) {
|
|
94
|
+
const allRates = await getTrafficApiService().getTollRates(ctx);
|
|
95
|
+
// Page the full set so structuredContent and content[] carry the identical page (the
|
|
96
|
+
// service stays filter-only; paging is a tool-handler concern). totalCount stays the
|
|
97
|
+
// full entry count so the agent knows how much lies beyond this page.
|
|
98
|
+
const totalCount = allRates.length;
|
|
99
|
+
const offset = input.offset ?? 0;
|
|
100
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
101
|
+
const rates = allRates.slice(offset, offset + limit);
|
|
102
|
+
const hasMore = offset + rates.length < totalCount;
|
|
103
|
+
const nextOffset = hasMore ? offset + rates.length : null;
|
|
104
|
+
ctx.log.info('Toll rates fetched', { totalCount, offset, limit, returned: rates.length });
|
|
105
|
+
ctx.enrich({ totalCount, nextOffset, hasMore });
|
|
106
|
+
if (totalCount === 0) {
|
|
74
107
|
ctx.enrich.notice('No toll rate data available. The WSDOT API may be temporarily unavailable — retry in 30 seconds.');
|
|
75
108
|
}
|
|
109
|
+
else if (rates.length === 0) {
|
|
110
|
+
ctx.enrich.notice(`Offset ${offset} is past the end of ${totalCount} toll rate entries. Use an offset between 0 and ${totalCount - 1}.`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const window = `Showing toll rates ${offset + 1}–${offset + rates.length} of ${totalCount}.`;
|
|
114
|
+
ctx.enrich.notice(hasMore ? `${window} Pass offset=${nextOffset} for the next page.` : window);
|
|
115
|
+
}
|
|
76
116
|
return { rates };
|
|
77
117
|
},
|
|
78
118
|
format: (result) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-toll-rates.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-toll-rates.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,EAAE;IACvD,KAAK,EAAE,gBAAgB;IACvB,WAAW,EACT,uGAAuG;QACvG,wFAAwF;QACxF,
|
|
1
|
+
{"version":3,"file":"get-toll-rates.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-toll-rates.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAE7E,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,EAAE;IACvD,KAAK,EAAE,gBAAgB;IACvB,WAAW,EACT,uGAAuG;QACvG,wFAAwF;QACxF,4EAA4E;QAC5E,0GAA0G;IAC5G,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CAAC,+EAA+E,CAAC;QAC5F,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,SAAS,CAAC;aACd,QAAQ,EAAE;aACV,QAAQ,CACP,gDAAgD,SAAS,kBAAkB,aAAa,GAAG,CAC5F;KACJ,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,KAAK,EAAE,CAAC;aACL,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;YACpF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YACjE,eAAe,EAAE,CAAC;iBACf,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,wFAAwF,CACzF;YACH,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YACvF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;YACnF,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;YACrF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;YACrF,iBAAiB,EAAE,CAAC;iBACjB,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,qCAAqC,CAAC;YAClD,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YACpF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;YACrF,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;YACvF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;YACjF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YACnF,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,kDAAkD,CAAC;SAChE,CAAC;aACD,QAAQ,CAAC,4CAA4C,CAAC,CAC1D;aACA,QAAQ,CAAC,sDAAsD,CAAC;KACpE,CAAC;IAEF,UAAU,EAAE;QACV,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,CAAC,gEAAgE,CAAC;QAC7E,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,+EAA+E,CAAC;QAC5F,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;QAC1F,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,2HAA2H,CAC5H;KACJ;IAED,MAAM,EAAE;QACN;YACE,MAAM,EAAE,iBAAiB;YACzB,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,+EAA+E;YACrF,SAAS,EAAE,IAAI;YACf,QAAQ,EACN,oFAAoF;SACvF;QACD;YACE,MAAM,EAAE,qBAAqB;YAC7B,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,8FAA8F;YACpG,SAAS,EAAE,KAAK;YAChB,QAAQ,EACN,oHAAoH;SACvH;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,QAAQ,GAAG,MAAM,oBAAoB,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAEhE,qFAAqF;QACrF,qFAAqF;QACrF,sEAAsE;QACtE,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;QACnC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,aAAa,CAAC;QAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;QACnD,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QAE1D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAE1F,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;QAEhD,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,MAAM,CACf,kGAAkG,CACnG,CAAC;QACJ,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,GAAG,CAAC,MAAM,CAAC,MAAM,CACf,UAAU,MAAM,uBAAuB,UAAU,mDAAmD,UAAU,GAAG,CAAC,GAAG,CACtH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,sBAAsB,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,OAAO,UAAU,GAAG,CAAC;YAC7F,GAAG,CAAC,MAAM,CAAC,MAAM,CACf,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,gBAAgB,UAAU,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAC5E,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,IAAI,cAAc,CAAC;YAC1C,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAC1B,IAAI,CAAC,CAAC,UAAU;gBAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;YAC9D,IAAI,CAAC,CAAC,eAAe;gBAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;YACzE,IAAI,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;gBAC7C,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACjF,KAAK,CAAC,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;YACpC,CAAC;YACD,IAAI,CAAC,CAAC,aAAa,IAAI,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;YAC5E,IAAI,CAAC,CAAC,WAAW,IAAI,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YACtE,IAAI,CAAC,CAAC,iBAAiB,IAAI,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5F,IAAI,CAAC,CAAC,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACvD,IAAI,CAAC,CAAC,aAAa,IAAI,IAAI,IAAI,CAAC,CAAC,cAAc,IAAI,IAAI;gBACrD,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,CAAC,WAAW,IAAI,IAAI,IAAI,CAAC,CAAC,YAAY,IAAI,IAAI;gBACjD,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,CAAC,WAAW;gBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -6,6 +6,8 @@ import { z } from '@cyanheads/mcp-ts-core';
|
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
export declare const getTravelTimes: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
8
|
route: z.ZodOptional<z.ZodString>;
|
|
9
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
9
11
|
}, z.core.$strip>, z.ZodObject<{
|
|
10
12
|
corridors: z.ZodArray<z.ZodObject<{
|
|
11
13
|
travelTimeId: z.ZodOptional<z.ZodNumber>;
|
|
@@ -41,6 +43,8 @@ export declare const getTravelTimes: import("@cyanheads/mcp-ts-core").ToolDefini
|
|
|
41
43
|
readonly recovery: "Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.";
|
|
42
44
|
}], {
|
|
43
45
|
readonly totalCount: z.ZodNumber;
|
|
46
|
+
readonly nextOffset: z.ZodNullable<z.ZodNumber>;
|
|
47
|
+
readonly hasMore: z.ZodBoolean;
|
|
44
48
|
readonly routeFilter: z.ZodOptional<z.ZodString>;
|
|
45
49
|
readonly notice: z.ZodOptional<z.ZodString>;
|
|
46
50
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-travel-times.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-travel-times.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"get-travel-times.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-travel-times.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAOjE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuPzB,CAAC"}
|
|
@@ -6,13 +6,16 @@ import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { routeMatches } from '../../../services/traffic/route-match.js';
|
|
8
8
|
import { getTrafficApiService } from '../../../services/traffic/traffic-service.js';
|
|
9
|
+
const DEFAULT_LIMIT = 50;
|
|
10
|
+
const MAX_LIMIT = 500;
|
|
9
11
|
export const getTravelTimes = tool('wsdot_get_travel_times', {
|
|
10
12
|
title: 'Get Travel Times',
|
|
11
13
|
description: 'Returns current vs. average travel times for named WA highway corridors (I-5, I-90, SR 520, SR 99, ' +
|
|
12
14
|
'I-405, SR 167, etc.). Use for "how congested is I-5?" or commute time estimates. ' +
|
|
13
15
|
'The route filter matches two ways: a route designation ("I-5", "5", "SR 520") returns every ' +
|
|
14
16
|
'corridor measured on that route, and any text also matches corridor names ("Everett"). ' +
|
|
15
|
-
'When current time exceeds average, the corridor is congested.'
|
|
17
|
+
'When current time exceeds average, the corridor is congested. ' +
|
|
18
|
+
'Results are paged — pass offset/limit to page through the full set (the notice reports the next offset).',
|
|
16
19
|
annotations: { readOnlyHint: true },
|
|
17
20
|
input: z.object({
|
|
18
21
|
route: z
|
|
@@ -22,6 +25,19 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
|
|
|
22
25
|
'corridor whose start or end point is on that route, whichever form the feed reports. ' +
|
|
23
26
|
'Any text also matches the corridor name as a case-insensitive substring, so "Everett" ' +
|
|
24
27
|
'finds the Seattle-Everett corridors. Omit to return all corridors.'),
|
|
28
|
+
offset: z
|
|
29
|
+
.number()
|
|
30
|
+
.int()
|
|
31
|
+
.min(0)
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('Zero-based index of the first corridor to return, for paging. Defaults to 0.'),
|
|
34
|
+
limit: z
|
|
35
|
+
.number()
|
|
36
|
+
.int()
|
|
37
|
+
.min(1)
|
|
38
|
+
.max(MAX_LIMIT)
|
|
39
|
+
.optional()
|
|
40
|
+
.describe(`Maximum corridors to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}.`),
|
|
25
41
|
}),
|
|
26
42
|
output: z.object({
|
|
27
43
|
corridors: z
|
|
@@ -77,7 +93,14 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
|
|
|
77
93
|
.describe('Travel time corridors matching the filter.'),
|
|
78
94
|
}),
|
|
79
95
|
enrichment: {
|
|
80
|
-
totalCount: z
|
|
96
|
+
totalCount: z
|
|
97
|
+
.number()
|
|
98
|
+
.describe('Total corridors matching the filter across all pages (not just this page).'),
|
|
99
|
+
nextOffset: z
|
|
100
|
+
.number()
|
|
101
|
+
.nullable()
|
|
102
|
+
.describe('Offset to pass to retrieve the next page, or null when this is the last page.'),
|
|
103
|
+
hasMore: z.boolean().describe('True when more corridors remain beyond the current page.'),
|
|
81
104
|
routeFilter: z
|
|
82
105
|
.string()
|
|
83
106
|
.optional()
|
|
@@ -85,7 +108,7 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
|
|
|
85
108
|
notice: z
|
|
86
109
|
.string()
|
|
87
110
|
.optional()
|
|
88
|
-
.describe('
|
|
111
|
+
.describe('Informational note about the page window, or guidance when no corridors matched the route filter or the offset ran past the end.'),
|
|
89
112
|
},
|
|
90
113
|
errors: [
|
|
91
114
|
{
|
|
@@ -113,19 +136,40 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
|
|
|
113
136
|
? all.filter((t) => t.name?.toLowerCase().includes(routeFilter) ||
|
|
114
137
|
[t.startPoint?.roadName, t.endPoint?.roadName].some((roadName) => roadName != null && routeMatches(routeFilter, roadName)))
|
|
115
138
|
: all;
|
|
116
|
-
|
|
139
|
+
// Page the full filtered set so structuredContent and content[] carry the identical
|
|
140
|
+
// page (the service stays filter-only; paging is a tool-handler concern). totalCount
|
|
141
|
+
// stays the full match count so the agent knows how much lies beyond this page.
|
|
142
|
+
const totalCount = filtered.length;
|
|
143
|
+
const offset = input.offset ?? 0;
|
|
144
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
145
|
+
const corridors = filtered.slice(offset, offset + limit).map((t) => ({
|
|
117
146
|
...t,
|
|
118
147
|
delayInMinutes: t.currentTimeInMinutes != null && t.averageTimeInMinutes != null
|
|
119
148
|
? t.currentTimeInMinutes - t.averageTimeInMinutes
|
|
120
149
|
: undefined,
|
|
121
150
|
}));
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
151
|
+
const hasMore = offset + corridors.length < totalCount;
|
|
152
|
+
const nextOffset = hasMore ? offset + corridors.length : null;
|
|
153
|
+
ctx.log.info('Travel times fetched', {
|
|
154
|
+
total: all.length,
|
|
155
|
+
totalCount,
|
|
156
|
+
offset,
|
|
157
|
+
limit,
|
|
158
|
+
returned: corridors.length,
|
|
159
|
+
});
|
|
160
|
+
ctx.enrich({ totalCount, nextOffset, hasMore, ...(routeFilter && { routeFilter }) });
|
|
161
|
+
if (totalCount === 0) {
|
|
125
162
|
ctx.enrich.notice(routeFilter
|
|
126
163
|
? `No corridors matched the route filter "${routeFilter}". Try a broader filter (e.g. "I-5" instead of "I-5 NB") or omit the filter to list all corridors.`
|
|
127
164
|
: 'No travel time data available. The WSDOT API may be temporarily unavailable — retry in 30 seconds.');
|
|
128
165
|
}
|
|
166
|
+
else if (corridors.length === 0) {
|
|
167
|
+
ctx.enrich.notice(`Offset ${offset} is past the end of ${totalCount} matching corridors. Use an offset between 0 and ${totalCount - 1}.`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const window = `Showing corridors ${offset + 1}–${offset + corridors.length} of ${totalCount}.`;
|
|
171
|
+
ctx.enrich.notice(hasMore ? `${window} Pass offset=${nextOffset} for the next page.` : window);
|
|
172
|
+
}
|
|
129
173
|
return { corridors };
|
|
130
174
|
},
|
|
131
175
|
format: (result) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-travel-times.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-travel-times.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAE7E,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,wBAAwB,EAAE;IAC3D,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,qGAAqG;QACrG,mFAAmF;QACnF,8FAA8F;QAC9F,yFAAyF;QACzF
|
|
1
|
+
{"version":3,"file":"get-travel-times.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-travel-times.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,8 @@ export declare const searchAlerts: import("@cyanheads/mcp-ts-core").ToolDefiniti
|
|
|
9
9
|
region: z.ZodOptional<z.ZodString>;
|
|
10
10
|
startMilepost: z.ZodOptional<z.ZodNumber>;
|
|
11
11
|
endMilepost: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
13
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
12
14
|
}, z.core.$strip>, z.ZodObject<{
|
|
13
15
|
alerts: z.ZodArray<z.ZodObject<{
|
|
14
16
|
alertId: z.ZodOptional<z.ZodNumber>;
|
|
@@ -51,6 +53,8 @@ export declare const searchAlerts: import("@cyanheads/mcp-ts-core").ToolDefiniti
|
|
|
51
53
|
readonly recovery: "Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.";
|
|
52
54
|
}], {
|
|
53
55
|
readonly totalCount: z.ZodNumber;
|
|
56
|
+
readonly nextOffset: z.ZodNullable<z.ZodNumber>;
|
|
57
|
+
readonly hasMore: z.ZodBoolean;
|
|
54
58
|
readonly appliedFilters: z.ZodObject<{
|
|
55
59
|
stateRoute: z.ZodOptional<z.ZodString>;
|
|
56
60
|
region: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-alerts.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-alerts.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"search-alerts.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-alerts.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAOjE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAySvB,CAAC"}
|
|
@@ -4,14 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
import { byIdThenContent } from '../../../services/traffic/stable-order.js';
|
|
7
8
|
import { getTrafficApiService } from '../../../services/traffic/traffic-service.js';
|
|
9
|
+
const DEFAULT_LIMIT = 50;
|
|
10
|
+
const MAX_LIMIT = 500;
|
|
8
11
|
export const searchAlerts = tool('wsdot_search_alerts', {
|
|
9
12
|
title: 'Search Highway Alerts',
|
|
10
13
|
description: 'Returns active WA highway alerts: incidents, construction, closures, and restrictions. ' +
|
|
11
14
|
'Filter by state route ("I-90", "90", "SR 520", or "520" all work), ' +
|
|
12
15
|
'WSDOT region (Northwest, Olympic, Southwest, South Central, North Central, Eastern), ' +
|
|
13
16
|
"or milepost range, matched against the alert's full extent. " +
|
|
14
|
-
'Omit all filters to return all current statewide alerts.'
|
|
17
|
+
'Omit all filters to return all current statewide alerts. ' +
|
|
18
|
+
'Results are ordered by alertId and paged — pass offset/limit to page through the full set ' +
|
|
19
|
+
'(the notice reports the next offset).',
|
|
15
20
|
annotations: { readOnlyHint: true },
|
|
16
21
|
input: z.object({
|
|
17
22
|
stateRoute: z
|
|
@@ -30,6 +35,19 @@ export const searchAlerts = tool('wsdot_search_alerts', {
|
|
|
30
35
|
.number()
|
|
31
36
|
.optional()
|
|
32
37
|
.describe('End of the milepost range. Matched by extent overlap like startMilepost, so an alert beginning inside the range and continuing past it is returned.'),
|
|
38
|
+
offset: z
|
|
39
|
+
.number()
|
|
40
|
+
.int()
|
|
41
|
+
.min(0)
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Zero-based index of the first alert to return, for paging. Defaults to 0.'),
|
|
44
|
+
limit: z
|
|
45
|
+
.number()
|
|
46
|
+
.int()
|
|
47
|
+
.min(1)
|
|
48
|
+
.max(MAX_LIMIT)
|
|
49
|
+
.optional()
|
|
50
|
+
.describe(`Maximum alerts to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}.`),
|
|
33
51
|
}),
|
|
34
52
|
output: z.object({
|
|
35
53
|
alerts: z
|
|
@@ -95,7 +113,14 @@ export const searchAlerts = tool('wsdot_search_alerts', {
|
|
|
95
113
|
.describe('Matching highway alerts.'),
|
|
96
114
|
}),
|
|
97
115
|
enrichment: {
|
|
98
|
-
totalCount: z
|
|
116
|
+
totalCount: z
|
|
117
|
+
.number()
|
|
118
|
+
.describe('Total alerts matching the filters across all pages (not just this page).'),
|
|
119
|
+
nextOffset: z
|
|
120
|
+
.number()
|
|
121
|
+
.nullable()
|
|
122
|
+
.describe('Offset to pass to retrieve the next page, or null when this is the last page.'),
|
|
123
|
+
hasMore: z.boolean().describe('True when more alerts remain beyond the current page.'),
|
|
99
124
|
appliedFilters: z
|
|
100
125
|
.object({
|
|
101
126
|
stateRoute: z.string().optional().describe('State route filter applied.'),
|
|
@@ -107,7 +132,7 @@ export const searchAlerts = tool('wsdot_search_alerts', {
|
|
|
107
132
|
notice: z
|
|
108
133
|
.string()
|
|
109
134
|
.optional()
|
|
110
|
-
.describe('
|
|
135
|
+
.describe('Informational note about the page window, or guidance when no alerts matched the filters or the offset ran past the end.'),
|
|
111
136
|
},
|
|
112
137
|
enrichmentTrailer: {
|
|
113
138
|
appliedFilters: {
|
|
@@ -146,26 +171,45 @@ export const searchAlerts = tool('wsdot_search_alerts', {
|
|
|
146
171
|
async handler(input, ctx) {
|
|
147
172
|
const stateRoute = input.stateRoute?.trim() || undefined;
|
|
148
173
|
const region = input.region?.trim() || undefined;
|
|
149
|
-
const
|
|
174
|
+
const fetched = await getTrafficApiService().searchAlerts({
|
|
150
175
|
...(stateRoute && { stateRoute }),
|
|
151
176
|
...(region && { region }),
|
|
152
177
|
...(input.startMilepost != null && { startMilepost: input.startMilepost }),
|
|
153
178
|
...(input.endMilepost != null && { endMilepost: input.endMilepost }),
|
|
154
179
|
}, ctx);
|
|
155
|
-
|
|
180
|
+
// The alerts feed serves one alert set in more than one row order, so a given offset is only
|
|
181
|
+
// reproducible once the rows are ordered here. Alerts with no alertId sort last.
|
|
182
|
+
const matched = fetched.toSorted(byIdThenContent((a) => a.alertId));
|
|
156
183
|
const appliedFilters = {
|
|
157
184
|
...(stateRoute && { stateRoute }),
|
|
158
185
|
...(region && { region }),
|
|
159
186
|
...(input.startMilepost != null && { startMilepost: input.startMilepost }),
|
|
160
187
|
...(input.endMilepost != null && { endMilepost: input.endMilepost }),
|
|
161
188
|
};
|
|
162
|
-
|
|
163
|
-
|
|
189
|
+
// Page the full filtered set so structuredContent and content[] carry the identical
|
|
190
|
+
// page (the service stays filter-only; paging is a tool-handler concern). totalCount
|
|
191
|
+
// stays the full match count so the agent knows how much lies beyond this page.
|
|
192
|
+
const totalCount = matched.length;
|
|
193
|
+
const offset = input.offset ?? 0;
|
|
194
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
195
|
+
const alerts = matched.slice(offset, offset + limit);
|
|
196
|
+
const hasMore = offset + alerts.length < totalCount;
|
|
197
|
+
const nextOffset = hasMore ? offset + alerts.length : null;
|
|
198
|
+
ctx.log.info('Alerts fetched', { totalCount, offset, limit, returned: alerts.length });
|
|
199
|
+
ctx.enrich({ totalCount, appliedFilters, nextOffset, hasMore });
|
|
200
|
+
if (totalCount === 0) {
|
|
164
201
|
const hasFilters = Object.keys(appliedFilters).length > 0;
|
|
165
202
|
ctx.enrich.notice(hasFilters
|
|
166
203
|
? 'No alerts matched the applied filters. Try removing the stateRoute, region, or milepost filters to broaden results.'
|
|
167
204
|
: 'No active highway alerts statewide at this time.');
|
|
168
205
|
}
|
|
206
|
+
else if (alerts.length === 0) {
|
|
207
|
+
ctx.enrich.notice(`Offset ${offset} is past the end of ${totalCount} matching alerts. Use an offset between 0 and ${totalCount - 1}.`);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const window = `Showing alerts ${offset + 1}–${offset + alerts.length} of ${totalCount}.`;
|
|
211
|
+
ctx.enrich.notice(hasMore ? `${window} Pass offset=${nextOffset} for the next page.` : window);
|
|
212
|
+
}
|
|
169
213
|
return { alerts };
|
|
170
214
|
},
|
|
171
215
|
format: (result) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-alerts.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-alerts.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,EAAE;IACtD,KAAK,EAAE,uBAAuB;IAC9B,WAAW,EACT,yFAAyF;QACzF,qEAAqE;QACrE,uFAAuF;QACvF,8DAA8D;QAC9D,
|
|
1
|
+
{"version":3,"file":"search-alerts.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-alerts.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-cameras.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-cameras.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"search-cameras.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-cameras.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAOjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwNxB,CAAC"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
import { byIdThenContent } from '../../../services/traffic/stable-order.js';
|
|
7
8
|
import { getTrafficApiService } from '../../../services/traffic/traffic-service.js';
|
|
8
9
|
const DEFAULT_LIMIT = 50;
|
|
9
10
|
const MAX_LIMIT = 500;
|
|
@@ -12,7 +13,8 @@ export const searchCameras = tool('wsdot_search_cameras', {
|
|
|
12
13
|
description: 'Returns WSDOT highway camera locations, descriptions, and image URLs. ' +
|
|
13
14
|
'Camera images are copyright WSDOT — only metadata and image URLs are returned, not image bytes. ' +
|
|
14
15
|
'Filter by state route ("I-90", "90", "SR 520", or "520" all work), WSDOT region, or milepost range. ' +
|
|
15
|
-
'Results are paged — pass offset/limit to page through the full set
|
|
16
|
+
'Results are ordered by cameraId and paged — pass offset/limit to page through the full set ' +
|
|
17
|
+
'(the notice reports the next offset).',
|
|
16
18
|
annotations: { readOnlyHint: true },
|
|
17
19
|
input: z.object({
|
|
18
20
|
stateRoute: z
|
|
@@ -124,12 +126,15 @@ export const searchCameras = tool('wsdot_search_cameras', {
|
|
|
124
126
|
async handler(input, ctx) {
|
|
125
127
|
const stateRoute = input.stateRoute?.trim() || undefined;
|
|
126
128
|
const region = input.region?.trim() || undefined;
|
|
127
|
-
const
|
|
129
|
+
const fetched = await getTrafficApiService().searchCameras({
|
|
128
130
|
...(stateRoute && { stateRoute }),
|
|
129
131
|
...(region && { region }),
|
|
130
132
|
...(input.startMilepost != null && { startMilepost: input.startMilepost }),
|
|
131
133
|
...(input.endMilepost != null && { endMilepost: input.endMilepost }),
|
|
132
134
|
}, ctx);
|
|
135
|
+
// The camera feed serves one camera set in more than one row order, so a given offset is only
|
|
136
|
+
// reproducible once the rows are ordered here. Cameras with no cameraId sort last.
|
|
137
|
+
const allCameras = fetched.toSorted(byIdThenContent((c) => c.cameraId));
|
|
133
138
|
const appliedFilters = {
|
|
134
139
|
...(stateRoute && { stateRoute }),
|
|
135
140
|
...(region && { region }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-cameras.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-cameras.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAE7E,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,sBAAsB,EAAE;IACxD,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EACT,wEAAwE;QACxE,kGAAkG;QAClG,sGAAsG;QACtG,
|
|
1
|
+
{"version":3,"file":"search-cameras.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-cameras.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Deterministic row ordering for the paged traffic feeds. WSDOT serves some feeds
|
|
3
|
+
* in more than one row order, and every page a caller requests is backed by a fresh upstream
|
|
4
|
+
* fetch, so a page window taken in arrival order both skips and repeats rows as the caller walks
|
|
5
|
+
* the offsets. Ordering a feed here before it is sliced makes a given offset reproducible.
|
|
6
|
+
* @module services/traffic/stable-order
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Builds a comparator that orders rows by a numeric id, rows without one last.
|
|
10
|
+
*
|
|
11
|
+
* The order is **total**: rows the id leaves tied — a repeated id, or two rows that both lack
|
|
12
|
+
* one — fall back to their serialized content. Without that fallback a tie group keeps whatever
|
|
13
|
+
* order upstream sent, and a page boundary landing inside the group reintroduces exactly the
|
|
14
|
+
* skip-and-repeat the ordering exists to prevent. Rows whose content is identical compare equal,
|
|
15
|
+
* which is harmless: either page carries the same record.
|
|
16
|
+
*
|
|
17
|
+
* @param idOf - Reads the row's numeric identifier, or `undefined` when the feed omitted it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function byIdThenContent<T>(idOf: (row: T) => number | undefined): (a: T, b: T) => number;
|
|
20
|
+
//# sourceMappingURL=stable-order.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stable-order.d.ts","sourceRoot":"","sources":["../../../src/services/traffic/stable-order.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,OAC1D,CAAC,KAAK,CAAC,KAAG,MAAM,CAO5B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Deterministic row ordering for the paged traffic feeds. WSDOT serves some feeds
|
|
3
|
+
* in more than one row order, and every page a caller requests is backed by a fresh upstream
|
|
4
|
+
* fetch, so a page window taken in arrival order both skips and repeats rows as the caller walks
|
|
5
|
+
* the offsets. Ordering a feed here before it is sliced makes a given offset reproducible.
|
|
6
|
+
* @module services/traffic/stable-order
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Builds a comparator that orders rows by a numeric id, rows without one last.
|
|
10
|
+
*
|
|
11
|
+
* The order is **total**: rows the id leaves tied — a repeated id, or two rows that both lack
|
|
12
|
+
* one — fall back to their serialized content. Without that fallback a tie group keeps whatever
|
|
13
|
+
* order upstream sent, and a page boundary landing inside the group reintroduces exactly the
|
|
14
|
+
* skip-and-repeat the ordering exists to prevent. Rows whose content is identical compare equal,
|
|
15
|
+
* which is harmless: either page carries the same record.
|
|
16
|
+
*
|
|
17
|
+
* @param idOf - Reads the row's numeric identifier, or `undefined` when the feed omitted it.
|
|
18
|
+
*/
|
|
19
|
+
export function byIdThenContent(idOf) {
|
|
20
|
+
return (a, b) => {
|
|
21
|
+
const byId = (idOf(a) ?? Number.MAX_SAFE_INTEGER) - (idOf(b) ?? Number.MAX_SAFE_INTEGER);
|
|
22
|
+
if (byId !== 0)
|
|
23
|
+
return byId;
|
|
24
|
+
const keyA = JSON.stringify(a);
|
|
25
|
+
const keyB = JSON.stringify(b);
|
|
26
|
+
return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=stable-order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stable-order.js","sourceRoot":"","sources":["../../../src/services/traffic/stable-order.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAI,IAAoC;IACrE,OAAO,CAAC,CAAI,EAAE,CAAI,EAAU,EAAE;QAC5B,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACzF,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/wsdot-mcp-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Query WA highway conditions, ferry schedules, vessel locations, toll rates, border waits, and alerts via MCP. STDIO or Streamable HTTP.",
|
|
5
5
|
"mcpName": "io.github.cyanheads/wsdot-mcp-server",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
"url": "https://wsdot.caseyjhand.com/mcp"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
|
-
"version": "0.2.
|
|
15
|
+
"version": "0.2.2",
|
|
16
16
|
"packages": [
|
|
17
17
|
{
|
|
18
18
|
"registryType": "npm",
|
|
19
19
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
20
20
|
"identifier": "@cyanheads/wsdot-mcp-server",
|
|
21
21
|
"runtimeHint": "node",
|
|
22
|
-
"version": "0.2.
|
|
22
|
+
"version": "0.2.2",
|
|
23
23
|
"packageArguments": [
|
|
24
24
|
{
|
|
25
25
|
"type": "positional",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
55
55
|
"identifier": "@cyanheads/wsdot-mcp-server",
|
|
56
56
|
"runtimeHint": "node",
|
|
57
|
-
"version": "0.2.
|
|
57
|
+
"version": "0.2.2",
|
|
58
58
|
"packageArguments": [
|
|
59
59
|
{
|
|
60
60
|
"type": "positional",
|