This example uses an app generation prompt together with MCP for ArcGIS Location Services (beta) to build an interactive JavaScript mapping application that enables users to perform geocoding, reverse geocoding, routing, and elevation queries. The AI agent is responsible for establishing a connection to the MCP server and invoking the available tools to power the application.

An example app built using MCP for ArcGIS Location
Services

Prerequisites

Your MCP client must be properly configured to access MCP for ArcGIS Location Services. For setup instructions, go to Get started.

Example

As a best practice, use a separate access token to render maps in your application. This token may be different from the one used by your MCP server.

  1. Create an API key with the following privilege(s) Privileges are a set of permissions assigned to ArcGIS accounts, developer credentials, and applications that grant access to secure resources and functionality in ArcGIS. Learn more :

    • Location services > Basemaps
  2. Create an .env file in the root of your project and add the API key:

    MAP_API_KEY=your_api_key_here
  3. Run the following prompt to build the application. Use the dropdown to select the language you want to use.

    Node.js Node.js Python
    Build a standalone Node.js chat-based map app using Express and MCP for ArcGIS Location Services.
    This is a chat-first application with an interactive map panel. Use the ArcGIS Maps SDK for JavaScript in the browser for map display, feature rendering, and extent fitting. Use the backend for MCP access, request orchestration, response normalization, and chat/session handling.
    Create:
    - server.js
    - package.json
    - mcp.example.json
    - README.md
    - public/index.html
    - public/app.js
    - public/styles.css
    Core features:
    - Chat-first interaction for supported ArcGIS Location Services workflows
    - Geocode (find_address_candidates)
    - Reverse geocode (reverse_geocode)
    - Route solve (solve_route)
    - Elevation (elevation_at_locations)
    - ArcGIS interactive map visualization using ArcGIS Maps SDK for JavaScript
    - Natural-language response text paired with normalized geographic output when available
    Supported chat behaviors:
    - Interpret user requests and map them to the supported MCP tools
    - Before calling MCP tools, classify each user request into one of: `geocode`, `reverse`, `route`, `elevation`, or `unsupported`
    - Only call the MCP tools required for the chosen classification
    - Return both:
    - natural-language answer text
    - structured geographic output normalized to GeoJSON FeatureCollection when map data exists
    - If no map data is available, still return a useful text answer
    - If the user asks for unsupported workflows such as drive-time polygons, service areas, or optimization, explain the limitation clearly instead of inventing unsupported MCP tool usage
    - For unsupported or text-only requests, return a successful response with a helpful answer and `geojson: null`
    MCP requirements:
    - Read `mcp.json` from the local folder, with fallback to `../mcp.json`
    - Use `servers.alp-mcp-server.url` + headers
    - JSON-RPC `initialize` + `tools/call`
    - Support JSON and SSE responses
    - Parse SSE data lines and use the last valid JSON payload
    - Normalize errors and tool output cleanly
    - Implement a reusable MCP client/helper for initialize and tool calls instead of duplicating request logic per route
    Credential split:
    - Keep MCP bearer token for MCP server auth
    - Use a separate browser map API key from `app.mapApiKey` or `MAP_API_KEY` / `ARCGIS_API_KEY`
    - Do not hardcode secrets
    HTTP routes:
    - GET /
    - GET /api/health
    - GET /api/tools
    - GET /api/arcgis-token
    - GET /arcgis-config.js
    - POST /api/chat
    - GET /api/chat/stream
    Chat/UI behavior:
    - ChatGPT-like layout with a scrolling conversation, user and assistant bubbles, input box, and submit button
    - Show friendly in-progress status text while requests are running
    - Preserve chat history during the browser session
    - Trim or summarize older chat history when needed so long conversations do not degrade app behavior
    - Render the map beside or below the chat depending on viewport width
    - Plot returned points and routes when available
    - Fit the map extent to returned features
    - Keep the app responsive for desktop and mobile
    Map behavior:
    - Render returned GeoJSON on the ArcGIS map using distinct symbology for points and routes
    - By default, replace prior assistant-result graphics when a new result arrives
    - If the user explicitly asks to keep or add to previous results, append graphics instead of replacing them
    - Keep map rendering driven by the normalized GeoJSON returned from the backend
    - If a response has text only, preserve the map state and show the text answer without forcing a map update
    Node.js implementation expectations:
    - Use Node.js for the MCP bridge, routing, config loading, chat orchestration, and token/config endpoints
    - Use Express to serve the HTML shell at `/` and static assets from `/public`
    - Use the native `fetch` API available in current Node.js or a single HTTP client dependency if needed, but keep dependencies minimal
    - Keep dependencies minimal: `express` and only add others if clearly needed
    - Default port 3000 with `PORT` override
    - Start the app with `node server.js`
    - Initialize the MCP session once at startup if practical; otherwise lazily initialize and cache the session state for reuse across requests
    - If `mcp.json` is missing, malformed, or missing `servers.alp-mcp-server`, fail clearly with a readable startup or request error
    - Document required configuration in README, including where `mcp.json` should live and how to run the app
    Route contracts:
    - `GET /` serves the main HTML page
    - `GET /api/health` returns a simple JSON health response
    - `GET /api/tools` returns the discovered MCP tools or a normalized error
    - `GET /api/arcgis-token` returns JSON containing the browser map credential, using the configured API key rather than the MCP bearer token
    - `GET /arcgis-config.js` returns a small JavaScript config payload the frontend can read
    - `POST /api/chat` accepts a user message and returns a normalized JSON chat response
    - `GET /api/chat/stream` provides server-sent events for the active chat request and emits event types `status`, `tool_call`, `result`, `error`, and `done`, finishing with the same normalized final payload shape as `POST /api/chat`
    Chat request contract:
    - Request JSON:
    - `message`: user prompt text
    - `history`: optional prior chat turns for conversational continuity
    - `context`: optional UI context such as selected coordinates or map extent
    - The server is responsible for choosing the appropriate supported MCP tools from the user request
    - The server must classify the request before calling tools and include the chosen classification in response metadata
    - The server must not invent unsupported tools or fabricated results
    - If history is too large, trim or summarize older turns while preserving enough context for the current request
    Chat response contract:
    - Success JSON:
    - `text`: assistant answer string
    - `geojson`: GeoJSON FeatureCollection or `null`
    - `toolCalls`: optional summary of which MCP tools were used
    - `meta`: optional normalized details such as request classification, geocode candidate count, route summary, or elevation point count
    - Error JSON:
    - `error`: object with `message`, `code`, and optional `details`
    GeoJSON normalization rules:
    - Geocode results normalize to `Point` features
    - Reverse geocode results normalize to a `Point` feature
    - Elevation results normalize to one or more `Point` features with elevation attributes
    - Route results normalize to a `LineString` feature
    - If a supported response has no usable geometry, return `geojson: null` and keep the text answer useful
    README expectations:
    - Include setup and run instructions for the Express app
    - Document required environment variables and browser map credential setup
    - Include example `mcp.json` placement and configuration notes
    - Include example chat prompts for geocode, reverse geocode, route, elevation, and unsupported requests
    Input and error handling:
    - Validate request bodies explicitly before processing
    - Return clear 4xx errors for invalid input and 5xx errors for upstream MCP failures
    - Surface MCP error messages in a normalized JSON shape the frontend can display
    - Handle empty results without crashing the UI
    - Keep response shapes consistent across success and error cases
    - Include clear user-facing handling for missing environment variables, MCP connection failures, rate limits, oversized prompts, and invalid or empty responses
    - Add retry behavior for transient upstream failures when reasonable, but do not hide persistent errors
    Acceptance:
    - App starts from the Node.js entrypoint and serves both API routes and frontend assets
    - Chat flow works end-to-end with MCP-powered tool usage
    - Geocode, reverse geocode, route, and elevation workflows are available through chat
    - The map renders returned point and route data when present
    - Responses include both text and GeoJSON when map data exists
    - Errors are human-readable and actionable

    The agent should:

    • Create a project folder on the local machine containing a working application
    • Provide instructions on how to run the application
    • Implement a custom connector to MCP for ArcGIS Location Services using the provided URL and access token
    • Use the connector to call MCP tools for geocoding, reverse geocoding, routing, and elevation based on user input
    • Build an interactive map interface that updates dynamically with results from MCP tool calls