Setting the file. One moment.
Mastra Example · Mapbox MCP Runtime Patterns · mapbox/mapbox-agent-skills · Skills Docs
ContentsBack to the top of the page Evals
examples/typescript/mastra-example.ts
examples/typescript/ mastra-example.ts
TypeScript · 251 lines · 8 KB
import
{ createTool }
from
'@mastra/core/tools'
;
16 import { z } from 'zod' ;
17
18 // Mapbox MCP Client (hosted server)
19 class MapboxMCP {
20 private url = 'https://mcp.mapbox.com/mcp' ;
21 private headers : Record < string , string >;
22
23 constructor ( token ?: string ) {
24 const mapboxToken = token || process.env. MAPBOX_ACCESS_TOKEN ;
25 if ( ! mapboxToken) {
26 throw new Error ( 'MAPBOX_ACCESS_TOKEN is required' );
27 }
28 this .headers = {
29 'Content-Type' : 'application/json' ,
30 'Authorization' : `Bearer ${ mapboxToken }`
31 };
32 }
33
34 async callTool ( name : string , args : any ) : Promise < any > {
35 const request = {
36 jsonrpc: '2.0' ,
37 id: Date. now (),
38 method: 'tools/call' ,
39 params: { name, arguments: args }
40 };
41
42 const response = await fetch ( this .url, {
43 method: 'POST' ,
44 headers: this .headers,
45 body: JSON . stringify (request)
46 });
47
48 if ( ! response.ok) {
49 throw new Error ( `MCP request failed: ${ response . statusText }` );
50 }
51
52 const data = await response. json () as any ;
53
54 if (data.error) {
55 throw new Error ( `MCP error: ${ data . error . message }` );
56 }
57
58 return JSON . parse (data.result.content[ 0 ].text);
59 }
60 }
61
62 // Initialize Mapbox MCP client
63 const mcp = new MapboxMCP ();
64
65 // Create Mapbox tools for Mastra
66 const getDirectionsTool = createTool ({
67 id: 'get-directions' ,
68 description: 'Get turn-by-turn driving directions with traffic-aware route distance and travel time along roads. Use when you need the actual driving route or traffic-aware duration.' ,
69 inputSchema: z. object ({
70 origin: z. array (z. number ()). length ( 2 ). describe ( 'Origin coordinates [longitude, latitude]' ),
71 destination: z. array (z. number ()). length ( 2 ). describe ( 'Destination coordinates [longitude, latitude]' ),
72 }),
73 outputSchema: z. object ({
74 duration: z. number (). describe ( 'Travel time in seconds' ),
75 distance: z. number (). describe ( 'Distance in meters' ),
76 summary: z. string (). describe ( 'Route summary' )
77 }),
78 execute : async ({ origin , destination }) => {
79 const result = await mcp. callTool ( 'directions_tool' , {
80 coordinates: [
81 { longitude: origin[ 0 ], latitude: origin[ 1 ] },
82 { longitude: destination[ 0 ], latitude: destination[ 1 ] }
83 ],
84 routing_profile: 'mapbox/driving-traffic'
85 });
86
87 return {
88 duration: result.routes[ 0 ].duration,
89 distance: result.routes[ 0 ].distance,
90 summary: `${ Math . round ( result . routes [ 0 ]. duration / 60 ) } min, ${ ( result . routes [ 0 ]. distance / 1000 ). toFixed ( 1 ) } km`
91 };
92 }
93 });
94
95 const searchPOITool = createTool ({
96 id: 'search-poi' ,
97 description: 'Find ALL places of a specific category type near a location. Use when user wants to browse places by type (restaurants, hotels, coffee, etc.), not search for a specific named place.' ,
98 inputSchema: z. object ({
99 category: z. string (). describe ( 'POI category: restaurant, hotel, coffee, gas_station, etc.' ),
100 location: z. array (z. number ()). length ( 2 ). describe ( 'Search center [longitude, latitude]' ),
101 }),
102 outputSchema: z. object ({
103 results: z. array (z. object ({
104 name: z. string (),
105 coordinates: z. array (z. number ()),
106 address: z. string (). optional ()
107 }))
108 }),
109 execute : async ({ category , location }) => {
110 const result = await mcp. callTool ( 'category_search_tool' , {
111 category,
112 proximity: { longitude: location[ 0 ], latitude: location[ 1 ] }
113 });
114
115 return {
116 results: result.features. map (( f : any ) => ({
117 name: f.properties.name,
118 coordinates: f.geometry.coordinates,
119 address: f.properties.address
120 }))
121 };
122 }
123 });
124
125 const calculateDistanceTool = createTool ({
126 id: 'calculate-distance' ,
127 description: 'Calculate straight-line (great-circle) distance between two points. Use for quick "as the crow flies" distance checks. Works offline, instant, no API cost.' ,
128 inputSchema: z. object ({
129 from: z. array (z. number ()). length ( 2 ). describe ( 'Start coordinates [longitude, latitude]' ),
130 to: z. array (z. number ()). length ( 2 ). describe ( 'End coordinates [longitude, latitude]' ),
131 units: z. enum ([ 'miles' , 'kilometers' ]). optional (). default ( 'miles' )
132 }),
133 outputSchema: z. object ({
134 distance: z. number (). describe ( 'Distance in specified units' )
135 }),
136 execute : async ({ from , to , units }) => {
137 const result = await mcp. callTool ( 'distance_tool' , {
138 from: { longitude: from[ 0 ], latitude: from[ 1 ] },
139 to: { longitude: to[ 0 ], latitude: to[ 1 ] },
140 units: units || 'miles'
141 });
142
143 return {
144 distance: parseFloat (result)
145 };
146 }
147 });
148
149 const getIsochroneTool = createTool ({
150 id: 'get-isochrone' ,
151 description: 'Calculate the AREA reachable within a time limit from a starting point. Use for "What can I reach in X minutes?" questions or service area analysis.' ,
152 inputSchema: z. object ({
153 location: z. array (z. number ()). length ( 2 ). describe ( 'Center point [longitude, latitude]' ),
154 minutes: z. number (). describe ( 'Time limit in minutes' ),
155 profile: z. enum ([ 'mapbox/driving' , 'mapbox/walking' , 'mapbox/cycling' ]). optional (). default ( 'mapbox/driving' )
156 }),
157 outputSchema: z. object ({
158 area: z. string (). describe ( 'GeoJSON polygon of reachable area' )
159 }),
160 execute : async ({ location , minutes , profile }) => {
161 const result = await mcp. callTool ( 'isochrone_tool' , {
162 coordinates: { longitude: location[ 0 ], latitude: location[ 1 ] },
163 contours_minutes: [minutes],
164 profile: profile || 'mapbox/driving'
165 });
166
167 return {
168 area: JSON . stringify (result)
169 };
170 }
171 });
172
173 // Create Mastra agent with Mapbox tools
174 const locationAgent = new Agent ({
175 id: 'location-agent' ,
176 name: 'Location Intelligence Agent' ,
177 instructions: `You are a location intelligence expert. You help users with:
178 - Finding places (restaurants, hotels, etc.)
179 - Planning routes with traffic
180 - Calculating distances and travel times
181 - Analyzing reachable areas
182
183 TOOL SELECTION RULES:
184 - Use calculate-distance for straight-line distance ("as the crow flies")
185 - Use get-directions for route distance along roads with traffic
186 - Use search-poi for finding types of places ("coffee shops", "restaurants")
187 - Use get-isochrone for "what can I reach in X minutes" questions
188 - Prefer offline tools (calculate-distance) when real-time data is not needed
189
190 Always provide clear, actionable information with specific times and distances.` ,
191 model: 'openai/gpt-5.2' ,
192 tools: {
193 getDirectionsTool,
194 searchPOITool,
195 calculateDistanceTool,
196 getIsochroneTool
197 }
198 });
199
200 // Example usage
201 async function main () {
202 try {
203 // Example 1: Find restaurants and calculate route
204 console. log ( 'Example 1: Finding restaurants near Times Square \n ' );
205
206 const response1 = await locationAgent. generate ([
207 {
208 role: 'user' ,
209 content: 'Find 3 restaurants near Times Square NYC (coordinates: -73.9857, 40.7484) and tell me how far each is.'
210 }
211 ]);
212
213 console. log ( 'Agent:' , response1.text);
214 console. log ( ' \n --- \n ' );
215
216 // Example 2: Plan a route
217 console. log ( 'Example 2: Planning route with traffic \n ' );
218
219 const response2 = await locationAgent. generate ([
220 {
221 role: 'user' ,
222 content: 'What is the driving time from Boston (-71.0589, 42.3601) to NYC (-74.0060, 40.7128) with current traffic?'
223 }
224 ]);
225
226 console. log ( 'Agent:' , response2.text);
227 console. log ( ' \n --- \n ' );
228
229 // Example 3: Isochrone analysis
230 console. log ( 'Example 3: Reachable area analysis \n ' );
231
232 const response3 = await locationAgent. generate ([
233 {
234 role: 'user' ,
235 content: 'Show me the area I can reach within 15 minutes driving from downtown SF (-122.4194, 37.7749)'
236 }
237 ]);
238
239 console. log ( 'Agent:' , response3.text);
240
241 } catch (error) {
242 console. error ( 'Error:' , error);
243 }
244 }
245
246 // Run if executed directly
247 if (require.main === module ) {
248 main ();
249 }
250
251 export { locationAgent, mcp };