@cyanheads/wsdot-mcp-server 0.2.5 → 0.3.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.
Files changed (64) hide show
  1. package/AGENTS.md +45 -18
  2. package/CLAUDE.md +45 -18
  3. package/README.md +77 -81
  4. package/changelog/0.2.x/0.2.6.md +29 -0
  5. package/changelog/0.3.x/0.3.0.md +30 -0
  6. package/changelog/template.md +9 -26
  7. package/dist/index.js +4 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/mcp-server/tools/definitions/get-border-waits.tool.d.ts +2 -0
  10. package/dist/mcp-server/tools/definitions/get-border-waits.tool.d.ts.map +1 -1
  11. package/dist/mcp-server/tools/definitions/get-border-waits.tool.js +3 -1
  12. package/dist/mcp-server/tools/definitions/get-border-waits.tool.js.map +1 -1
  13. package/dist/mcp-server/tools/definitions/get-ferry-alerts.tool.d.ts +2 -0
  14. package/dist/mcp-server/tools/definitions/get-ferry-alerts.tool.d.ts.map +1 -1
  15. package/dist/mcp-server/tools/definitions/get-ferry-alerts.tool.js +2 -0
  16. package/dist/mcp-server/tools/definitions/get-ferry-alerts.tool.js.map +1 -1
  17. package/dist/mcp-server/tools/definitions/get-ferry-routes.tool.d.ts +2 -0
  18. package/dist/mcp-server/tools/definitions/get-ferry-routes.tool.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/get-ferry-routes.tool.js +3 -1
  20. package/dist/mcp-server/tools/definitions/get-ferry-routes.tool.js.map +1 -1
  21. package/dist/mcp-server/tools/definitions/get-ferry-schedule.tool.d.ts +2 -0
  22. package/dist/mcp-server/tools/definitions/get-ferry-schedule.tool.d.ts.map +1 -1
  23. package/dist/mcp-server/tools/definitions/get-ferry-schedule.tool.js +11 -7
  24. package/dist/mcp-server/tools/definitions/get-ferry-schedule.tool.js.map +1 -1
  25. package/dist/mcp-server/tools/definitions/get-ferry-terminals.tool.d.ts +2 -0
  26. package/dist/mcp-server/tools/definitions/get-ferry-terminals.tool.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/get-ferry-terminals.tool.js +3 -1
  28. package/dist/mcp-server/tools/definitions/get-ferry-terminals.tool.js.map +1 -1
  29. package/dist/mcp-server/tools/definitions/get-mountain-passes.tool.d.ts +2 -0
  30. package/dist/mcp-server/tools/definitions/get-mountain-passes.tool.d.ts.map +1 -1
  31. package/dist/mcp-server/tools/definitions/get-mountain-passes.tool.js +3 -1
  32. package/dist/mcp-server/tools/definitions/get-mountain-passes.tool.js.map +1 -1
  33. package/dist/mcp-server/tools/definitions/get-terminal-space.tool.d.ts +2 -0
  34. package/dist/mcp-server/tools/definitions/get-terminal-space.tool.d.ts.map +1 -1
  35. package/dist/mcp-server/tools/definitions/get-terminal-space.tool.js +4 -0
  36. package/dist/mcp-server/tools/definitions/get-terminal-space.tool.js.map +1 -1
  37. package/dist/mcp-server/tools/definitions/get-toll-rates.tool.d.ts +6 -0
  38. package/dist/mcp-server/tools/definitions/get-toll-rates.tool.d.ts.map +1 -1
  39. package/dist/mcp-server/tools/definitions/get-toll-rates.tool.js +126 -80
  40. package/dist/mcp-server/tools/definitions/get-toll-rates.tool.js.map +1 -1
  41. package/dist/mcp-server/tools/definitions/get-travel-times.tool.d.ts +2 -0
  42. package/dist/mcp-server/tools/definitions/get-travel-times.tool.d.ts.map +1 -1
  43. package/dist/mcp-server/tools/definitions/get-travel-times.tool.js +105 -101
  44. package/dist/mcp-server/tools/definitions/get-travel-times.tool.js.map +1 -1
  45. package/dist/mcp-server/tools/definitions/get-vessel-locations.tool.d.ts +2 -0
  46. package/dist/mcp-server/tools/definitions/get-vessel-locations.tool.d.ts.map +1 -1
  47. package/dist/mcp-server/tools/definitions/get-vessel-locations.tool.js +3 -1
  48. package/dist/mcp-server/tools/definitions/get-vessel-locations.tool.js.map +1 -1
  49. package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts +12 -0
  50. package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts.map +1 -1
  51. package/dist/mcp-server/tools/definitions/search-alerts.tool.js +155 -131
  52. package/dist/mcp-server/tools/definitions/search-alerts.tool.js.map +1 -1
  53. package/dist/mcp-server/tools/definitions/search-cameras.tool.d.ts +14 -0
  54. package/dist/mcp-server/tools/definitions/search-cameras.tool.d.ts.map +1 -1
  55. package/dist/mcp-server/tools/definitions/search-cameras.tool.js +121 -68
  56. package/dist/mcp-server/tools/definitions/search-cameras.tool.js.map +1 -1
  57. package/dist/mcp-server/tools/page-budget.d.ts +56 -0
  58. package/dist/mcp-server/tools/page-budget.d.ts.map +1 -0
  59. package/dist/mcp-server/tools/page-budget.js +76 -0
  60. package/dist/mcp-server/tools/page-budget.js.map +1 -0
  61. package/dist/services/ferry/ferry-service.js +3 -3
  62. package/dist/services/traffic/traffic-service.js +3 -3
  63. package/package.json +10 -9
  64. package/server.json +3 -3
@@ -4,7 +4,9 @@
4
4
  */
5
5
  import { tool, z } from '@cyanheads/mcp-ts-core';
6
6
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
- import { coordinatePair } from '../../../mcp-server/tools/coordinate-pair.js';
7
+ import { coordinatePair } from '../coordinate-pair.js';
8
+ import { continuationNotice, fitPageToBudget, MAX_FILTER_LENGTH, PAGE_BYTE_BUDGET, renderPage, } from '../page-budget.js';
9
+ import { routeMatches } from '../../../services/traffic/route-match.js';
8
10
  import { getTrafficApiService } from '../../../services/traffic/traffic-service.js';
9
11
  const DEFAULT_LIMIT = 50;
10
12
  const MAX_LIMIT = 500;
@@ -19,16 +21,47 @@ function routeDesignation(stateRoute) {
19
21
  const number = stateRoute.replace(/^0+(?=\d)/, '');
20
22
  return INTERSTATE_ROUTE_NUMBERS.has(number) ? `I-${number}` : `SR ${number}`;
21
23
  }
24
+ const TollRateSchema = z
25
+ .object({
26
+ tripName: z.string().optional().describe('Name of the tolled trip or lane segment.'),
27
+ stateRoute: z
28
+ .string()
29
+ .optional()
30
+ .describe('Route number as the feed reports it: bare and zero-padded, with no route type ("099", "405"). The rendered text shows the posted designation (SR 99, I-405).'),
31
+ travelDirection: z
32
+ .string()
33
+ .optional()
34
+ .describe('Direction code the feed assigns the toll trip: N, S, E, or W. On SR 99, SR 509, and SR 520 it is one fixed code per facility (S, S, and E) although trips run both ways, so read the direction of travel from the segment ends — startLocationName/endLocationName and startMilepost → endMilepost — not from this code.'),
35
+ startMilepost: z.number().optional().describe('Starting milepost of the toll segment.'),
36
+ endMilepost: z.number().optional().describe('Ending milepost of the toll segment.'),
37
+ tollRateInDollars: z.number().optional().describe('Current toll rate in US dollars.'),
38
+ message: z.string().optional().describe('Dynamic message associated with this toll.'),
39
+ startLocationName: z.string().optional().describe('Human-readable start location name.'),
40
+ endLocationName: z.string().optional().describe('Human-readable end location name.'),
41
+ startLatitude: z.number().optional().describe('Latitude of the segment start point.'),
42
+ startLongitude: z.number().optional().describe('Longitude of the segment start point.'),
43
+ endLatitude: z.number().optional().describe('Latitude of the segment end point.'),
44
+ endLongitude: z.number().optional().describe('Longitude of the segment end point.'),
45
+ timeUpdated: z.string().optional().describe('When this toll rate was last updated (ISO 8601).'),
46
+ })
47
+ .describe('Current toll rate for one segment or trip.');
22
48
  export const getTollRates = tool('wsdot_get_toll_rates', {
23
49
  title: 'Get Toll Rates',
24
50
  description: 'Returns current dynamic toll rates for WA express lanes and tolled facilities: SR 99 (WSDOT Tunnel), ' +
25
51
  'SR 167 HOT Lanes, I-405 Express Lanes, SR 509 tolled segment, and the SR 520 Bridge. ' +
26
52
  'Rates are time-banded and change dynamically based on traffic conditions. ' +
27
- 'stateRoute is a bare, zero-padded route number ("099", "405") — the posted designation is in ' +
28
- 'the rendered text. Results are paged — pass offset/limit to page through the full set ' +
29
- '(the notice reports the next offset).',
53
+ 'Filter to one facility with stateRoute ("SR 520", "520", "I-405", or "405" all work). ' +
54
+ 'Each row reports stateRoute as the bare, zero-padded number the feed carries ("099", "405") — ' +
55
+ 'the posted designation is in the rendered text. Results are paged — pass offset/limit to page ' +
56
+ 'through the matching set. ' +
57
+ `A page ends at limit or at a ${PAGE_BYTE_BUDGET.toLocaleString('en-US')}-byte response budget, whichever comes first; the notice reports the next offset.`,
30
58
  annotations: { readOnlyHint: true },
31
59
  input: z.object({
60
+ stateRoute: z
61
+ .string()
62
+ .max(MAX_FILTER_LENGTH)
63
+ .optional()
64
+ .describe('Tolled route to filter by. Accepts natural forms — "SR 520", "520", "0520", "I-405", "405" — matched case- and space-insensitively against each row\'s posted designation, so a route-type prefix must agree: "SR 405" matches nothing because the I-405 Express Lanes are an Interstate. A route with no tolled facility returns an empty page whose notice names the tolled routes. Omit to include every facility.'),
32
65
  offset: z
33
66
  .number()
34
67
  .int()
@@ -41,52 +74,39 @@ export const getTollRates = tool('wsdot_get_toll_rates', {
41
74
  .min(1)
42
75
  .max(MAX_LIMIT)
43
76
  .optional()
44
- .describe(`Maximum toll rates to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}.`),
77
+ .describe(`Maximum toll rates to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}. A large page ends sooner, at the ${PAGE_BYTE_BUDGET.toLocaleString('en-US')}-byte response budget.`),
45
78
  }),
46
79
  output: z.object({
47
80
  rates: z
48
- .array(z
49
- .object({
50
- tripName: z.string().optional().describe('Name of the tolled trip or lane segment.'),
51
- stateRoute: z.string().optional().describe('State route number.'),
52
- travelDirection: z
53
- .string()
54
- .optional()
55
- .describe('Travel direction code for this toll segment: N (north), S (south), E (east), W (west).'),
56
- startMilepost: z.number().optional().describe('Starting milepost of the toll segment.'),
57
- endMilepost: z.number().optional().describe('Ending milepost of the toll segment.'),
58
- tollRateInDollars: z.number().optional().describe('Current toll rate in US dollars.'),
59
- message: z.string().optional().describe('Dynamic message associated with this toll.'),
60
- startLocationName: z
61
- .string()
62
- .optional()
63
- .describe('Human-readable start location name.'),
64
- endLocationName: z.string().optional().describe('Human-readable end location name.'),
65
- startLatitude: z.number().optional().describe('Latitude of the segment start point.'),
66
- startLongitude: z.number().optional().describe('Longitude of the segment start point.'),
67
- endLatitude: z.number().optional().describe('Latitude of the segment end point.'),
68
- endLongitude: z.number().optional().describe('Longitude of the segment end point.'),
69
- timeUpdated: z
70
- .string()
71
- .optional()
72
- .describe('When this toll rate was last updated (ISO 8601).'),
73
- })
74
- .describe('Current toll rate for one segment or trip.'))
75
- .describe('Current toll rates for all active tolled facilities.'),
81
+ .array(TollRateSchema)
82
+ .describe('Current toll rates for the matching tolled facilities.'),
76
83
  }),
77
84
  enrichment: {
78
85
  totalCount: z
79
86
  .number()
80
- .describe('Total toll rate entries across all pages (not just this page).'),
87
+ .describe('Total toll rate entries matching the filter across all pages (not just this page).'),
81
88
  nextOffset: z
82
89
  .number()
83
90
  .nullable()
84
91
  .describe('Offset to pass to retrieve the next page, or null when this is the last page.'),
85
92
  hasMore: z.boolean().describe('True when more toll rates remain beyond the current page.'),
93
+ appliedFilters: z
94
+ .object({
95
+ stateRoute: z.string().optional().describe('State route filter applied.'),
96
+ })
97
+ .optional()
98
+ .describe('Active filters applied to the toll rates. Absent when no filter was applied.'),
86
99
  notice: z
87
100
  .string()
88
101
  .optional()
89
- .describe('Informational note about the page window, or guidance when no toll rate data is available or the offset ran past the end.'),
102
+ .describe('Informational note about the page window, or guidance when no toll rate data is available, the route has no tolled facility, or the offset ran past the end.'),
103
+ },
104
+ enrichmentTrailer: {
105
+ appliedFilters: {
106
+ render: (filters) => filters?.stateRoute
107
+ ? `**Applied Filters:**\n- **Route:** ${filters.stateRoute}`
108
+ : '**Applied Filters:** none',
109
+ },
90
110
  },
91
111
  errors: [
92
112
  {
@@ -95,6 +115,7 @@ export const getTollRates = tool('wsdot_get_toll_rates', {
95
115
  when: 'WSDOT Traffic API is unreachable or returns a non-2xx response after retries.',
96
116
  retryable: true,
97
117
  recovery: 'Retry in 30 seconds. If the issue persists, check wsdot.wa.gov for service status.',
118
+ thrownBy: 'service',
98
119
  },
99
120
  {
100
121
  reason: 'invalid_access_code',
@@ -102,30 +123,55 @@ export const getTollRates = tool('wsdot_get_toll_rates', {
102
123
  when: 'WSDOT rejected the request because WSDOT_ACCESS_CODE is missing, invalid, or not registered.',
103
124
  retryable: false,
104
125
  recovery: 'Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.',
126
+ thrownBy: 'service',
105
127
  },
106
128
  ],
107
129
  async handler(input, ctx) {
130
+ const stateRoute = input.stateRoute?.trim() || undefined;
108
131
  const allRates = await getTrafficApiService().getTollRates(ctx);
109
- // Page the full set so structuredContent and content[] carry the identical page (the
110
- // service stays filter-only; paging is a tool-handler concern). totalCount stays the
111
- // full entry count so the agent knows how much lies beyond this page.
112
- const totalCount = allRates.length;
132
+ // The feed value carries no route type, so it is matched as its posted designation — a bare
133
+ // "405" would otherwise let "SR 405" return the I-405 Express Lanes.
134
+ const matched = stateRoute
135
+ ? allRates.filter((r) => r.stateRoute != null && routeMatches(stateRoute, routeDesignation(r.stateRoute)))
136
+ : allRates;
137
+ // Page the matching set so structuredContent and content[] carry the identical page (the
138
+ // service stays fetch-only; filtering and paging are tool-handler concerns). totalCount
139
+ // stays the full match count so the agent knows how much lies beyond this page.
140
+ const totalCount = matched.length;
113
141
  const offset = input.offset ?? 0;
114
142
  const limit = input.limit ?? DEFAULT_LIMIT;
115
- const rates = allRates.slice(offset, offset + limit);
143
+ const requested = matched.slice(offset, offset + limit);
144
+ const rates = fitPageToBudget(requested, renderTollRate, stateRoute);
116
145
  const hasMore = offset + rates.length < totalCount;
117
146
  const nextOffset = hasMore ? offset + rates.length : null;
118
147
  ctx.log.info('Toll rates fetched', { totalCount, offset, limit, returned: rates.length });
119
- ctx.enrich({ totalCount, nextOffset, hasMore });
120
- if (totalCount === 0) {
148
+ ctx.enrich({
149
+ totalCount,
150
+ nextOffset,
151
+ hasMore,
152
+ ...(stateRoute && { appliedFilters: { stateRoute } }),
153
+ });
154
+ if (allRates.length === 0) {
121
155
  ctx.enrich.notice('No toll rate data available. The WSDOT API may be temporarily unavailable — retry in 30 seconds.');
122
156
  }
157
+ else if (totalCount === 0) {
158
+ // Dedupe the designations, not the raw values — "099" and "99" are one facility.
159
+ const tolled = [
160
+ ...new Set(allRates
161
+ .flatMap((r) => (r.stateRoute ? [r.stateRoute] : []))
162
+ .toSorted((a, b) => Number.parseInt(a, 10) - Number.parseInt(b, 10))
163
+ .map(routeDesignation)),
164
+ ];
165
+ ctx.enrich.notice(`No tolled facility on ${stateRoute}. The feed carries tolls on ${tolled.join(', ')} — pass one of those, or omit stateRoute for every facility.`);
166
+ }
123
167
  else if (rates.length === 0) {
124
168
  ctx.enrich.notice(`Offset ${offset} is past the end of ${totalCount} toll rate entries. Use an offset between 0 and ${totalCount - 1}.`);
125
169
  }
126
170
  else {
127
- const window = `Showing toll rates ${offset + 1}–${offset + rates.length} of ${totalCount}.`;
128
- ctx.enrich.notice(hasMore ? `${window} Pass offset=${nextOffset} for the next page.` : window);
171
+ const shown = `Showing toll rates ${offset + 1}–${offset + rates.length} of ${totalCount}.`;
172
+ ctx.enrich.notice(nextOffset === null
173
+ ? shown
174
+ : `${shown} ${continuationNotice(nextOffset, rates.length < requested.length)}`);
129
175
  }
130
176
  return { rates };
131
177
  },
@@ -133,42 +179,42 @@ export const getTollRates = tool('wsdot_get_toll_rates', {
133
179
  if (result.rates.length === 0) {
134
180
  return [{ type: 'text', text: 'No toll rate data available.' }];
135
181
  }
136
- const lines = [];
137
- for (const r of result.rates) {
138
- // tripName is an opaque upstream key ("099tp03268"); the endpoint names read as a segment,
139
- // so they lead. A segment whose ends carry the same name collapses to one.
140
- const ends = [r.startLocationName, r.endLocationName].filter(Boolean);
141
- const segment = [...new Set(ends)].join(' → ');
142
- lines.push(`### ${segment || r.tripName || 'Toll segment'}`);
143
- if (r.tripName)
144
- lines.push(`**Trip:** ${r.tripName}`);
145
- if (r.stateRoute)
146
- lines.push(`**Route:** ${routeDesignation(r.stateRoute)}`);
147
- if (r.travelDirection)
148
- lines.push(`**Direction:** ${r.travelDirection}`);
149
- if (r.startLocationName)
150
- lines.push(`**From:** ${r.startLocationName}`);
151
- if (r.endLocationName)
152
- lines.push(`**To:** ${r.endLocationName}`);
153
- if (r.startMilepost != null)
154
- lines.push(`**Start MP:** ${r.startMilepost}`);
155
- if (r.endMilepost != null)
156
- lines.push(`**End MP:** ${r.endMilepost}`);
157
- if (r.tollRateInDollars != null)
158
- lines.push(`**Rate:** $${r.tollRateInDollars.toFixed(2)}`);
159
- if (r.message)
160
- lines.push(`**Message:** ${r.message}`);
161
- const startCoords = coordinatePair(r.startLatitude, r.startLongitude);
162
- if (startCoords)
163
- lines.push(`**Start Coords:** ${startCoords}`);
164
- const endCoords = coordinatePair(r.endLatitude, r.endLongitude);
165
- if (endCoords)
166
- lines.push(`**End Coords:** ${endCoords}`);
167
- if (r.timeUpdated)
168
- lines.push(`**Updated:** ${r.timeUpdated}`);
169
- lines.push('');
170
- }
171
- return [{ type: 'text', text: lines.join('\n') }];
182
+ return [{ type: 'text', text: renderPage(result.rates, renderTollRate) }];
172
183
  },
173
184
  });
185
+ /** One toll rate's `content[]` block — shared by `format()` and the page-budget charge. */
186
+ function renderTollRate(r) {
187
+ // tripName is an opaque upstream key ("099tp03268"); the endpoint names read as a segment,
188
+ // so they lead. A segment whose ends carry the same name collapses to one.
189
+ const ends = [r.startLocationName, r.endLocationName].filter(Boolean);
190
+ const segment = [...new Set(ends)].join(' → ');
191
+ const lines = [`### ${segment || r.tripName || 'Toll segment'}`];
192
+ if (r.tripName)
193
+ lines.push(`**Trip:** ${r.tripName}`);
194
+ if (r.stateRoute)
195
+ lines.push(`**Route:** ${routeDesignation(r.stateRoute)}`);
196
+ if (r.travelDirection)
197
+ lines.push(`**Direction:** ${r.travelDirection}`);
198
+ if (r.startLocationName)
199
+ lines.push(`**From:** ${r.startLocationName}`);
200
+ if (r.endLocationName)
201
+ lines.push(`**To:** ${r.endLocationName}`);
202
+ if (r.startMilepost != null)
203
+ lines.push(`**Start MP:** ${r.startMilepost}`);
204
+ if (r.endMilepost != null)
205
+ lines.push(`**End MP:** ${r.endMilepost}`);
206
+ if (r.tollRateInDollars != null)
207
+ lines.push(`**Rate:** $${r.tollRateInDollars.toFixed(2)}`);
208
+ if (r.message)
209
+ lines.push(`**Message:** ${r.message}`);
210
+ const startCoords = coordinatePair(r.startLatitude, r.startLongitude);
211
+ if (startCoords)
212
+ lines.push(`**Start Coords:** ${startCoords}`);
213
+ const endCoords = coordinatePair(r.endLatitude, r.endLongitude);
214
+ if (endCoords)
215
+ lines.push(`**End Coords:** ${endCoords}`);
216
+ if (r.timeUpdated)
217
+ lines.push(`**Updated:** ${r.timeUpdated}`);
218
+ return lines.join('\n');
219
+ }
174
220
  //# sourceMappingURL=get-toll-rates.tool.js.map
@@ -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":"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"}
1
+ {"version":3,"file":"get-toll-rates.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-toll-rates.tool.ts"],"names":[],"mappings":"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"}
@@ -35,12 +35,14 @@ export declare const getTravelTimes: import("@cyanheads/mcp-ts-core").ToolDefini
35
35
  readonly when: "WSDOT Traffic API is unreachable or returns a non-2xx response after retries.";
36
36
  readonly retryable: true;
37
37
  readonly recovery: "Retry in 30 seconds. If the issue persists, check wsdot.wa.gov for service status.";
38
+ readonly thrownBy: "service";
38
39
  }, {
39
40
  readonly reason: "invalid_access_code";
40
41
  readonly code: JsonRpcErrorCode.ConfigurationError;
41
42
  readonly when: "WSDOT rejected the request because WSDOT_ACCESS_CODE is missing, invalid, or not registered.";
42
43
  readonly retryable: false;
43
44
  readonly recovery: "Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.";
45
+ readonly thrownBy: "service";
44
46
  }], {
45
47
  readonly totalCount: z.ZodNumber;
46
48
  readonly nextOffset: z.ZodNullable<z.ZodNumber>;
@@ -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;AAOjE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuPzB,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;AAqEjE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2JzB,CAAC"}
@@ -4,8 +4,55 @@
4
4
  */
5
5
  import { tool, z } from '@cyanheads/mcp-ts-core';
6
6
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { continuationNotice, fitPageToBudget, MAX_FILTER_LENGTH, PAGE_BYTE_BUDGET, renderPage, } from '../page-budget.js';
7
8
  import { routeMatches } from '../../../services/traffic/route-match.js';
8
9
  import { getTrafficApiService } from '../../../services/traffic/traffic-service.js';
10
+ const CorridorSchema = z
11
+ .object({
12
+ travelTimeId: z.number().optional().describe('Unique corridor identifier.'),
13
+ name: z.string().optional().describe('Corridor name (e.g. "I-5: Northgate to Downtown").'),
14
+ description: z.string().optional().describe('Additional corridor description.'),
15
+ currentTimeInMinutes: z
16
+ .number()
17
+ .optional()
18
+ .describe('Current travel time in minutes. Absent when WSDOT reports no measurement for the corridor — a reversible express lane closed in this direction reports none.'),
19
+ averageTimeInMinutes: z
20
+ .number()
21
+ .optional()
22
+ .describe('Historical average travel time in minutes. Absent when WSDOT reports no measurement for the corridor.'),
23
+ delayInMinutes: z
24
+ .number()
25
+ .optional()
26
+ .describe('Delay above average in minutes. Positive means congestion. Absent when either travel time is unavailable.'),
27
+ timeUpdated: z
28
+ .string()
29
+ .optional()
30
+ .describe('When the travel time data was last updated (ISO 8601).'),
31
+ distanceInMiles: z.number().optional().describe('Corridor distance in miles.'),
32
+ startPoint: z
33
+ .object({
34
+ roadName: z.string().optional().describe('Road name at the start.'),
35
+ direction: z
36
+ .string()
37
+ .optional()
38
+ .describe('Travel direction code: N (north), S (south), E (east), W (west).'),
39
+ milePost: z.number().optional().describe('Starting milepost.'),
40
+ })
41
+ .optional()
42
+ .describe('Start of the measured corridor.'),
43
+ endPoint: z
44
+ .object({
45
+ roadName: z.string().optional().describe('Road name at the end.'),
46
+ direction: z
47
+ .string()
48
+ .optional()
49
+ .describe('Travel direction code: N (north), S (south), E (east), W (west).'),
50
+ milePost: z.number().optional().describe('Ending milepost.'),
51
+ })
52
+ .optional()
53
+ .describe('End of the measured corridor.'),
54
+ })
55
+ .describe('Travel time data for one highway corridor.');
9
56
  const DEFAULT_LIMIT = 50;
10
57
  const MAX_LIMIT = 500;
11
58
  export const getTravelTimes = tool('wsdot_get_travel_times', {
@@ -15,11 +62,13 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
15
62
  'The route filter matches two ways: a route designation ("I-5", "5", "SR 520") returns every ' +
16
63
  'corridor measured on that route, and any text also matches corridor names ("Everett"). ' +
17
64
  '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).',
65
+ 'Results are paged — pass offset/limit to page through the full set. ' +
66
+ `A page ends at limit or at a ${PAGE_BYTE_BUDGET.toLocaleString('en-US')}-byte response budget, whichever comes first; the notice reports the next offset.`,
19
67
  annotations: { readOnlyHint: true },
20
68
  input: z.object({
21
69
  route: z
22
70
  .string()
71
+ .max(MAX_FILTER_LENGTH)
23
72
  .optional()
24
73
  .describe('Optional filter. A route designation — "I-5", "5", "005", "SR 520", "520" — matches every ' +
25
74
  'corridor whose start or end point is on that route, whichever form the feed reports. ' +
@@ -37,60 +86,10 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
37
86
  .min(1)
38
87
  .max(MAX_LIMIT)
39
88
  .optional()
40
- .describe(`Maximum corridors to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}.`),
89
+ .describe(`Maximum corridors to return in this page (1–${MAX_LIMIT}). Defaults to ${DEFAULT_LIMIT}. A large page ends sooner, at the ${PAGE_BYTE_BUDGET.toLocaleString('en-US')}-byte response budget.`),
41
90
  }),
42
91
  output: z.object({
43
- corridors: z
44
- .array(z
45
- .object({
46
- travelTimeId: z.number().optional().describe('Unique corridor identifier.'),
47
- name: z
48
- .string()
49
- .optional()
50
- .describe('Corridor name (e.g. "I-5: Northgate to Downtown").'),
51
- description: z.string().optional().describe('Additional corridor description.'),
52
- currentTimeInMinutes: z
53
- .number()
54
- .optional()
55
- .describe('Current travel time in minutes. Absent when WSDOT reports no measurement for the corridor — a reversible express lane closed in this direction reports none.'),
56
- averageTimeInMinutes: z
57
- .number()
58
- .optional()
59
- .describe('Historical average travel time in minutes. Absent when WSDOT reports no measurement for the corridor.'),
60
- delayInMinutes: z
61
- .number()
62
- .optional()
63
- .describe('Delay above average in minutes. Positive means congestion. Absent when either travel time is unavailable.'),
64
- timeUpdated: z
65
- .string()
66
- .optional()
67
- .describe('When the travel time data was last updated (ISO 8601).'),
68
- distanceInMiles: z.number().optional().describe('Corridor distance in miles.'),
69
- startPoint: z
70
- .object({
71
- roadName: z.string().optional().describe('Road name at the start.'),
72
- direction: z
73
- .string()
74
- .optional()
75
- .describe('Travel direction code: N (north), S (south), E (east), W (west).'),
76
- milePost: z.number().optional().describe('Starting milepost.'),
77
- })
78
- .optional()
79
- .describe('Start of the measured corridor.'),
80
- endPoint: z
81
- .object({
82
- roadName: z.string().optional().describe('Road name at the end.'),
83
- direction: z
84
- .string()
85
- .optional()
86
- .describe('Travel direction code: N (north), S (south), E (east), W (west).'),
87
- milePost: z.number().optional().describe('Ending milepost.'),
88
- })
89
- .optional()
90
- .describe('End of the measured corridor.'),
91
- })
92
- .describe('Travel time data for one highway corridor.'))
93
- .describe('Travel time corridors matching the filter.'),
92
+ corridors: z.array(CorridorSchema).describe('Travel time corridors matching the filter.'),
94
93
  }),
95
94
  enrichment: {
96
95
  totalCount: z
@@ -117,6 +116,7 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
117
116
  when: 'WSDOT Traffic API is unreachable or returns a non-2xx response after retries.',
118
117
  retryable: true,
119
118
  recovery: 'Retry in 30 seconds. If the issue persists, check wsdot.wa.gov for service status.',
119
+ thrownBy: 'service',
120
120
  },
121
121
  {
122
122
  reason: 'invalid_access_code',
@@ -124,6 +124,7 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
124
124
  when: 'WSDOT rejected the request because WSDOT_ACCESS_CODE is missing, invalid, or not registered.',
125
125
  retryable: false,
126
126
  recovery: 'Register an access code at https://wsdot.wa.gov/traffic/api/, set WSDOT_ACCESS_CODE on the server, and restart it.',
127
+ thrownBy: 'service',
127
128
  },
128
129
  ],
129
130
  async handler(input, ctx) {
@@ -142,12 +143,13 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
142
143
  const totalCount = filtered.length;
143
144
  const offset = input.offset ?? 0;
144
145
  const limit = input.limit ?? DEFAULT_LIMIT;
145
- const corridors = filtered.slice(offset, offset + limit).map((t) => ({
146
+ const requested = filtered.slice(offset, offset + limit).map((t) => ({
146
147
  ...t,
147
148
  delayInMinutes: t.currentTimeInMinutes != null && t.averageTimeInMinutes != null
148
149
  ? t.currentTimeInMinutes - t.averageTimeInMinutes
149
150
  : undefined,
150
151
  }));
152
+ const corridors = fitPageToBudget(requested, renderCorridor, routeFilter);
151
153
  const hasMore = offset + corridors.length < totalCount;
152
154
  const nextOffset = hasMore ? offset + corridors.length : null;
153
155
  ctx.log.info('Travel times fetched', {
@@ -167,8 +169,10 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
167
169
  ctx.enrich.notice(`Offset ${offset} is past the end of ${totalCount} matching corridors. Use an offset between 0 and ${totalCount - 1}.`);
168
170
  }
169
171
  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
+ const shown = `Showing corridors ${offset + 1}–${offset + corridors.length} of ${totalCount}.`;
173
+ ctx.enrich.notice(nextOffset === null
174
+ ? shown
175
+ : `${shown} ${continuationNotice(nextOffset, corridors.length < requested.length)}`);
172
176
  }
173
177
  return { corridors };
174
178
  },
@@ -176,51 +180,51 @@ export const getTravelTimes = tool('wsdot_get_travel_times', {
176
180
  if (result.corridors.length === 0) {
177
181
  return [{ type: 'text', text: 'No corridors matched.' }];
178
182
  }
179
- const lines = [];
180
- for (const c of result.corridors) {
181
- lines.push(`### ${c.name ?? 'Corridor'}`);
182
- if (c.description)
183
- lines.push(c.description);
184
- lines.push(c.currentTimeInMinutes != null
185
- ? `**Current:** ${c.currentTimeInMinutes} min`
186
- : '**Current:** Not available — WSDOT reports no measurement for this corridor');
187
- if (c.averageTimeInMinutes != null)
188
- lines.push(`**Average:** ${c.averageTimeInMinutes} min`);
189
- if (c.delayInMinutes != null) {
190
- const sign = c.delayInMinutes > 0 ? '+' : '';
191
- lines.push(`**Delay:** ${sign}${c.delayInMinutes} min${c.delayInMinutes > 0 ? ' (congested)' : ''}`);
192
- }
193
- if (c.distanceInMiles != null)
194
- lines.push(`**Distance:** ${c.distanceInMiles} mi`);
195
- if (c.startPoint) {
196
- const sp = [
197
- c.startPoint.roadName,
198
- c.startPoint.direction,
199
- c.startPoint.milePost != null ? `MP ${c.startPoint.milePost}` : undefined,
200
- ]
201
- .filter(Boolean)
202
- .join(' ');
203
- if (sp)
204
- lines.push(`**From:** ${sp}`);
205
- }
206
- if (c.endPoint) {
207
- const ep = [
208
- c.endPoint.roadName,
209
- c.endPoint.direction,
210
- c.endPoint.milePost != null ? `MP ${c.endPoint.milePost}` : undefined,
211
- ]
212
- .filter(Boolean)
213
- .join(' ');
214
- if (ep)
215
- lines.push(`**To:** ${ep}`);
216
- }
217
- if (c.timeUpdated)
218
- lines.push(`**Updated:** ${c.timeUpdated}`);
219
- if (c.travelTimeId != null)
220
- lines.push(`**ID:** ${c.travelTimeId}`);
221
- lines.push('');
222
- }
223
- return [{ type: 'text', text: lines.join('\n') }];
183
+ return [{ type: 'text', text: renderPage(result.corridors, renderCorridor) }];
224
184
  },
225
185
  });
186
+ /** One corridor's `content[]` block — shared by `format()` and the page-budget charge. */
187
+ function renderCorridor(c) {
188
+ const lines = [`### ${c.name ?? 'Corridor'}`];
189
+ if (c.description)
190
+ lines.push(c.description);
191
+ lines.push(c.currentTimeInMinutes != null
192
+ ? `**Current:** ${c.currentTimeInMinutes} min`
193
+ : '**Current:** Not available — WSDOT reports no measurement for this corridor');
194
+ if (c.averageTimeInMinutes != null)
195
+ lines.push(`**Average:** ${c.averageTimeInMinutes} min`);
196
+ if (c.delayInMinutes != null) {
197
+ const sign = c.delayInMinutes > 0 ? '+' : '';
198
+ lines.push(`**Delay:** ${sign}${c.delayInMinutes} min${c.delayInMinutes > 0 ? ' (congested)' : ''}`);
199
+ }
200
+ if (c.distanceInMiles != null)
201
+ lines.push(`**Distance:** ${c.distanceInMiles} mi`);
202
+ if (c.startPoint) {
203
+ const sp = [
204
+ c.startPoint.roadName,
205
+ c.startPoint.direction,
206
+ c.startPoint.milePost != null ? `MP ${c.startPoint.milePost}` : undefined,
207
+ ]
208
+ .filter(Boolean)
209
+ .join(' ');
210
+ if (sp)
211
+ lines.push(`**From:** ${sp}`);
212
+ }
213
+ if (c.endPoint) {
214
+ const ep = [
215
+ c.endPoint.roadName,
216
+ c.endPoint.direction,
217
+ c.endPoint.milePost != null ? `MP ${c.endPoint.milePost}` : undefined,
218
+ ]
219
+ .filter(Boolean)
220
+ .join(' ');
221
+ if (ep)
222
+ lines.push(`**To:** ${ep}`);
223
+ }
224
+ if (c.timeUpdated)
225
+ lines.push(`**Updated:** ${c.timeUpdated}`);
226
+ if (c.travelTimeId != null)
227
+ lines.push(`**ID:** ${c.travelTimeId}`);
228
+ return lines.join('\n');
229
+ }
226
230
  //# sourceMappingURL=get-travel-times.tool.js.map