Israel Hiking MCP
Currently, you can only use the ping tool to check server liveness, retrieve version and data attribution info, and optionally echo a string. The server is in early development and will eventually provide tools for place search, route search, route details, POIs along a route, and routing. All data comes from Israel Hiking Map/Mapeak and is under CC BY-NC-SA 3.0 and ODbL licenses.
Provides tools for searching places, finding nearby hiking routes, retrieving detailed route geometry, discovering points of interest along a route, and planning walking routes using OpenStreetMap and Israel Hiking Map data.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Israel Hiking MCPPing the server to verify it's working."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Israel Hiking MCP
An MCP server that puts Israel Hiking Map / Mapeak trail data in reach of an LLM host. Five tools answer the questions a walk starts with: where a place is, what routes are mapped near it, what one of those routes actually looks like, what the map draws beside it, and how to get from one point to another.
search_places "Haifa" → 32.8191, 34.9984, ranked, linked
search_hiking_routes 15 km around it, 4–12 km → 16 routes, the 10 nearest first
get_route_details OSM/relation_13207704 → the Haifa Trail as GeoJSON, 903 positions
find_pois_along_route that route, 1 km, Water → 3 water features, distances in metres
route_between_points two points on the Carmel → 6.39 km walking path, both ends snappedEvery answer is grounded: it names its sources and their licences, lists the questions the data cannot settle, and flags the results somebody might act on. That is what the design turns on — an answer about a trail is only worth repeating if it says where it came from and where it stops.
Status: v0.1.0, feature-complete. Five tools built across nine reviewed pull requests, ~4,900 lines of typed Python under strict mypy, 409 offline tests and an opt-in live group. It is a personal-scale project pointed at a volunteer-run service — read Responsible use before pointing anything automated at it.
The map data belongs to Israel Hiking Map and OpenStreetMap, under licences that make everything this server returns non-commercial and share-alike. Read LICENSE-NOTICE.md before using any output.
What it does
Reads the map's own sources rather than scraping its pages. Places come from the site's search index. Routes and points of interest are decoded from the vector tiles the map itself draws (
global_points, zoom 10–14), which is the only place they exist — there is no query API for them. Route geometry comes from the OpenStreetMap API and from the site's user-shared routes; paths come from its routing engine.Assembles geometry that arrives in pieces. An OSM route is a relation of ways, each drawn in whatever direction its mapper chose and listed in whatever order the relation holds. The server sews them into continuous lines, follows nested relations breadth-first under a request budget, and returns a
MultiLineString— saying so — where the mapping genuinely does not join up. A user-shared route of more than 3,000 positions is thinned by Douglas-Peucker at the smallest tolerance that fits, and reports which tolerance that was, how many positions it kept, and that the ends survived.Ranks candidates and lets the host choose. Searches return an ordered list and say what they dropped — upstream's place index is worldwide, so "Haifa" reaches Syria, France and Chile first, and results are ranked into an Israel bounding box with the omissions counted in
warnings. Ordering is deterministic: the same inputs give the same routes in the same sequence.Works to a budget and says when it hits one. An area search costs one tile request per tile it covers, growing with the square of the radius, so it runs under a tile budget and refuses with a radius that would have worked rather than returning part of an area as though it were all of it. The zoom it searches at was picked for that budget and then checked against zoom-14 children over four regions to confirm nothing is dropped at the lower zoom.
Carries its provenance and its limits into the model's context. Every response ships an
attributionobject naming both sources, awarningslist, anunknownslist of what the data cannot establish — closure, access, water, waymarking, terrain, time — and a per-resultcautionon the things people act on. Water above all: a spring on this map is an undated record in a country where most water is seasonal, so the caution rides on the water result itself, and survives a summary that keeps the points and drops the warnings.Fails in a typed, stable way. Ten error codes, split into the transient and the permanent, with upstream bodies, URLs and tracebacks kept out of the message and sent to the log instead. A response in a shape the server does not recognise is reported as
upstream_schema_changedrather than read optimistically, and an unresolvable source is refused by name.Touches nothing upstream. Every request is a GET, identified by a descriptive User-Agent, capped in concurrency, timed out, cached in memory and retried at most once after a transient failure.
Related MCP server: MCP Ping-Pong Server
How it is built
Python 3.11+ on
FastMCP, withhttpxfor both upstreams,shapelyandmercantilefor geometry and tile maths, andmapbox-vector-tilefor decoding.Pydantic models are the contract. Their field descriptions travel to the client as each tool's output schema, so they are written to be read by a model and not only by a Python caller. A feature is always identified by a
{source, identifier}ref, never a bare id.Two upstreams, two clients.
mapeak.comandapi.openstreetmap.orgare different hosts under different usage policies, so they get separate connection pools and caches rather than a shared one that blurs which is being spent.Strict
mypyandruffover source and tests, with local stubs for the few third-party names worth describing.409 offline tests. Every upstream response is either a fixture in the shape a live one was observed in, or a vector tile built in-test with
mapbox-vector-tile's own encoder — so the tile path is exercised against real encoded bytes without committing any map data.An opt-in live group that asserts contract rather than content against the real hosts, catching what a fixture cannot: a renamed field, a moved endpoint, a routing type upstream stopped recognising.
CI on Python 3.11, 3.12 and 3.13 across Linux and Windows, with the live group on a workflow of its own.
Measured numbers carry their dates. Upstream keeps moving: measurements a day apart disagreed about how many disconnected pieces the Haifa Trail resolves to and what the Israel National Trail's corridor costs in tiles. The acceptance run below is the whole server driven through a real MCP session against the live hosts, with its output.
Install
There is nothing to clone. uv is the only
prerequisite — it fetches a suitable Python (3.11+) itself.
Claude Code:
claude mcp add israel-hiking -- uvx --from git+https://github.com/tisheldev/israel-hiking-mcp israel-hiking-mcpClaude Desktop — claude_desktop_config.json, then restart the app:
{
"mcpServers": {
"israel-hiking": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/tisheldev/israel-hiking-mcp",
"israel-hiking-mcp"
]
}
}
}Any other MCP client takes the same three things: the command uvx, the
arguments above, and stdio transport. Environment variables from the
Configuration table go in an "env" object beside
"command".
To hold a known version rather than whatever main holds, append a tag to the
URL — git+https://github.com/tisheldev/israel-hiking-mcp@v0.1.0. Without one,
every launch resolves the default branch, which is fine for trying it and worth
pinning for anything you rely on.
Run uvx --from git+https://github.com/tisheldev/israel-hiking-mcp israel-hiking-mcp --help
to check the install without a host attached. Run it with no arguments and it
will sit there saying nothing useful, which is correct: it is waiting for a
client on stdin. It says so before it waits.
Working on it
From a clone, for changing the code rather than using it:
uv sync
uv run israel-hiking-mcpThe server communicates over stdio and produces no stdout output of its own —
stdout is reserved for the JSON-RPC message stream. Logs go to stderr; set
IHM_LOG_LEVEL=DEBUG for verbose output.
CONTRIBUTING.md covers the rest: the checks, what the live test group costs, and what a bug report needs.
Tests
uv run pytestThe suite runs fully offline: every upstream response is either a fixture in
the shape a live one was observed in, or a vector tile built in-test with
mapbox-vector-tile's own encoder. No map data is committed, because none of it
is this project's to redistribute.
A second, opt-in group talks to the real hosts and is deselected by default:
uv run pytest -m liveThat is the run which catches what a fixture cannot — a renamed field, a moved endpoint, a routing type upstream stopped recognising. It asserts contract rather than content (that a route comes back with an identity, a name, a link and its cautions — not which routes are near Haifa today), and costs about a dozen requests. See tests/test_live.py.
Running a clone from a host
The Install section above is what to hand somebody else. To point a
host at a working copy instead — so an edit is picked up on the next restart —
give it uv and an absolute path:
claude mcp add israel-hiking-dev -- uv --directory /absolute/path/to/israel-hiking-mcp run israel-hiking-mcpThe path must be absolute; the host does not run in this directory.
Try it with MCP Inspector
npx @modelcontextprotocol/inspector uv run israel-hiking-mcpSet the working directory to this repository, connect, and open the Tools tab. Calling the five in order walks the whole server:
search_placeswithquery: "Haifa"→ Haifa, Israel first, with anihmUrlthat opens on the map site, and a warning saying how many worldwide matches were dropped.search_hiking_routeswith those coordinates,radiusKm: 15,minLengthKm: 4,maxLengthKm: 12→ Haifa Trail sections, Nakeb routes and shared routes, nearest first.get_route_detailswith therefof any of them.{"source": "OSM", "identifier": "relation_13207704"}is the Haifa Trail, assembled from the ways it is mapped as; aUsersref comes back with its author's own title, description and recorded climb;{"source": "OSM", "identifier": "relation_282071"}is the Israel National Trail — 2,480 ways and 41,689 recorded positions, returned as one continuous line thinned to fit; and{"source": "Nakeb", "identifier": "255"}is refused asunsupported_source.find_pois_along_routewith the Haifa Trail ref,bufferMeters: 1000andcategories: ["Water"]→ three water features, each with the samecaution, under a warning saying not to plan water on any of them. The Israel National Trail's ref shows the tile budget refusing a corridor too long to scan.route_between_pointsbetween two points on the Carmel → a calculated line, with the warning that nobody has walked it.
The acceptance run below is that walk, with its output.
Tools
Tool | Description |
| Find places by name (Hebrew or English) and return ranked candidate coordinates, each with a |
| List hiking routes mapped near a point, nearest first, with length, any difficulty rating, and a link to the map site. |
| Resolve one route ref into its GeoJSON line plus the title, description, length, climb and difficulty its source records. Resolves OSM and user-shared routes. |
| List the springs, caves, viewpoints and other mapped points within a given distance of a route's line, nearest first, each with its distance in metres. |
| Calculate a path between two points for walking, cycling or 4x4, using the map site's own routing engine. The one tool here whose answer is computed rather than recorded. |
search_places
Argument | Type | Default | Notes |
| string | — | Place name, 2–100 characters after trimming |
| boolean |
| Drop matches outside the Israel bounding box |
|
|
| Language of the returned names, and of the |
| integer |
| 1–20 |
Resolves a name — in Hebrew or English — into ranked candidate coordinates,
each with a {source, identifier} ref that the route and POI tools accept and
an ihmUrl that opens the place on the map site. It is the entry point for
everything else here: the {lat, lng} it returns is the shape
search_hiking_routes and route_between_points take.
Upstream's search is a worldwide index — "Haifa" matches places in Syria,
the United States, France and Chile before it reaches Haifa, Israel. Results
are therefore ranked by whether they fall inside an approximate bounding box
around Israel (29.3–33.4 N, 34.2–35.9 E), and by default the rest are dropped;
the warnings field always says when that happened. The box is a ranking
device, not a border: it is axis-aligned, so it also takes in parts of
neighbouring territory.
No match is not an error — the tool returns an empty places list with a
warning explaining what to try next. The tool never picks a candidate for you.
search_hiking_routes
Argument | Type | Default | Notes |
|
| — | Point to search around; |
| number |
| 1–40, measured to each route's start marker |
| number | null |
| 0–1000 |
| number | null |
| 0–1000 |
|
|
| See below |
|
|
| Language of names, descriptions and the |
| integer |
| 1–20 |
Returns the hiking routes mapped around a point, nearest first, each with its
length, any difficulty its source records, a {source, identifier} ref for
get_route_details and find_pois_along_route, and a link to the map site.
The routes are read out of the map's vector tiles, which is where they live —
the same tiles carry cycling and 4x4 routes, which this tool does not search.
Results are deterministic: the same centre, radius and constraints produce
the same routes in the same order, sorted by distance from the search centre
and then by {source, identifier}. Distances are great-circle, reported to
10 m, and are not walking distances.
Two upstream quirks the tool mirrors deliberately, and reports in warnings:
Most routes carry no difficulty rating. Upstream's own route filter keeps an unrated route whatever difficulty is asked for, and so does this tool — dropping them would empty almost every search. Each such result carries
difficulty: null, and a warning says how many were kept that way.A route the map does not name is not returned. The map site hides those features too; the count of skipped markers appears in
warnings.
A route with no length in the map data is returned with lengthKm: null, and
cannot satisfy a length range.
Nothing in a result establishes that a route is open, marked, passable,
permitted, or safe. description is the mapper's own undated note, and is
often the only place a closure or hazard is recorded.
get_route_details
Argument | Type | Default | Notes |
|
| — | The |
|
|
| Preferred language where the source holds both |
Returns the route's line as GeoJSON (LineString, or MultiLineString when the
route's parts do not join up), with startPoint, title, description,
activity, difficulty, lengthKm, ascentMeters, descentMeters and a link
to the map site.
Two sources resolve: OSM and Users. Nakeb, iNature and Wikidata
return unsupported_source rather than a guessed URL; the ihmUrl from the
search result opens any of them on the map site meanwhile.
Geometry is GeoJSON, so its positions are [longitude, latitude] — the
opposite order to every other coordinate this server returns.
source: "OSM"
Identifiers look like relation_282071, way_12345 or node_67890, which is
what the search returns. Geometry comes from api.openstreetmap.org
directly, as the map site's own frontend does — a second host, under
OSM's usage policy, with
the same identifying User-Agent and the same caching as every other request
here.
A route is a relation of ways, each way drawn in whatever direction its mapper
drew it and listed in whatever order the relation holds; ways whose ends
coincide are sewn back into continuous lines. Where the mapped ways genuinely do
not meet, the result is a MultiLineString and a warning says so — the whole
Haifa Trail came back as 24 disconnected pieces on 2026-08-15, which is the
mapping and not a failure to join it. A node is refused as invalid_input
without asking OSM: a point cannot be a route.
/full returns a relation's members but not the members of relations nested
inside it, so a trail split into sections costs one request per section. That
recursion is bounded by IHM_MAX_OSM_REQUESTS_PER_TOOL_CALL (16), follows
sections breadth-first, visits each relation once however often it is
referenced, and past the budget fails with geometry_too_large rather than
returning part of a trail as if it were all of it.
Everything reported besides the geometry is an OSM tag, so most of it is absent
on most routes: lengthKm comes from distance only, ascentMeters and
descentMeters from ascent/descent, difficulty from a difficulty tag
that happens to name one of upstream's four grades, and activity from route
in the map site's own words (hiking/foot → Hiking, bicycle/mtb →
Bicycle, road + scenic=yes → 4x4). The non-standard length tag is
deliberately not read — a sampled Haifa Trail section tags length=3 where the
map's own computed length is 8.59 km. For length, use the lengthKm of the
search result that produced the ref.
source: "Users"
A share stores a route as segments cut at each point its author dropped, each
restating the previous segment's last point. Those are joined into one line and
the repeated junction positions are dropped. A share holding several routes
comes back as a MultiLineString. Positions are reported to six decimals, about
0.11 m.
A route of more than 3,000 positions is thinned by Douglas-Peucker at the
smallest tolerance that brings it under that cap — 10 m, then 25, 50, 100 —
measured in a local equirectangular frame. geometryDetail reports
recordedPointCount, pointCount, simplified and toleranceMeters, and a
warning says the same in words. Every kept position is one the recorded line
really passed through, and the first and last always survive. A shape still
over the cap at 100 m fails with geometry_too_large rather than being
truncated.
Every response carries a fixed unknowns list — closure and access status,
water, waymarking and terrain, time required. These are properties of the data,
not of the particular route: the map records where somebody went, not whether
going there is currently a good idea.
find_pois_along_route
Argument | Type | Default | Notes |
|
| — | The same ref |
| number |
| 25–2000, straight-line distance to the route's drawn line |
| list of category | null |
| Defaults to Water, Natural, Historic, Viewpoint, Camping |
|
|
| Language of names, descriptions and the |
| integer |
| 1–50 |
Resolves the route through the same adapters as get_route_details, then
returns the map's points of interest within bufferMeters of its line, nearest
first. Each carries category, subtype, coordinates,
distanceFromRouteMeters and a link to the map site.
Water results are the ones people act on, and the ones to be careful with.
A spring, cistern, waterhole or pool here is a feature somebody recorded on a
map at an unrecorded date. Nothing establishes that it is flowing, reachable,
permitted or safe to drink, and most water in this country is seasonal. Every
water result carries that in a caution field of its own — not only in
warnings, so that a summary keeping the points and dropping the warnings still
carries it — and a warning repeats it at the head of the list.
Distances are straight lines from the route's recorded line, unthinned: this tool returns numbers about a route rather than the route itself, so nothing is simplified first. They are not walking distances, and say nothing about whether anything leads there — a spring 80 m off the trail may be 80 m down a cliff.
Categories are upstream's, not this server's. The plan for this tool was to
port the map site's osm-tags.service.ts mapping from raw OSM tags to
categories; a live zoom-12 tile settles it differently. Sampled over Haifa on
2026-08-15, every feature carried poiCategory, poiIcon and poiIconColor
and not one raw OSM tag — the tag mapping has already run by the time the
tileset is cut. So the category is read, and only the naming is ported:
poiIcon back to the label the map site puts on that icon in its own POI
category list. subtype is null for an icon that list does not name, including
icon-search, upstream's fallback for a feature it recognised only well enough
to draw.
Category | Subtypes |
| Spring, Pond · Waterfall · Waterhole · Water Well · Cistern · Stream, River |
| Cave · Tree · Flowers · Peak, Ridge, Valley |
| Ruins · Archaeological Site · Memorial |
| Viewpoint |
| Picnic Area · Campsite · Alpine Hut |
| Place · Attraction · Artwork · Synagogue · Church · Mosque · Place of Worship · Accommodation · Nature Reserve, National Park · iNature Entry · Wikipedia Entry |
Other is upstream's bucket for whatever its mapping did not place, and it
outnumbers everything else in a built-up area — 111 of 168 features in a
sampled Haifa tile. It is therefore excluded unless asked for. The route
categories (Hiking, Bicycle, 4x4) share those tiles and are never
returned here; search_hiking_routes is where they belong.
A stream or river is mapped as a line and marked at one point of it, so its distance is to that mark rather than to wherever the route crosses the water. When one is in the result, a warning says so.
What a scan costs is set by how long the route is, not by the buffer: the
corridor is fetched as map tiles, which are kilometres across. A local trail
costs one or two; the Israel National Trail's corridor cost 128 tiles at zoom 12
when it was measured on 2026-08-15, over the budget of 100, and fails with
search_area_too_large saying that a narrower buffer would still need 119 —
resolve one of its sections instead.
An empty list means nothing of that kind is mapped near this route. It is
not evidence that there is no water, and every response says so in unknowns.
route_between_points
Argument | Type | Default | Notes |
|
| — | Where to start; |
|
| — | Where to finish |
|
|
| Each uses a different set of ways |
Asks the map site's own routing engine for a path between two points and
returns it as a GeoJSON LineString, with three profiles to choose from —
walking, cycling and 4x4, each over a different set of ways. It is the one tool
here that answers a question the map does not already hold an answer to.
Which is also the thing to keep in mind: its answer is a computation rather than a record. Everything else this server returns is something a person put on a map. This is a line a routing engine drew just now by joining ways in a graph: nobody has walked it, and nothing in it knows about a gate, a fence, a firing zone or a stream in flood. Every response leads with a warning saying so, and it is not conditional on anything.
Returns the path as a GeoJSON LineString, its lengthKm measured along the
line, the straightLineKm between the two points for comparison, and both ends
as {requested, onPath, metersApart} — because a path starts where the router
can, not where it was asked to. The ends are snapped to the nearest mapped
way, which in open country can be hundreds of metres away, and covering that
ground is a walk the path does not include. Past 100 m either end says so in
warnings too.
Upstream sends an elevation with every position. It is dropped: it is interpolated from a profile sampled every 30 m, and the numbers worth computing from it — total climb, above all — would be noise dressed as data.
Bounds: both points must be inside the area the map covers (about 29.3–33.4 N,
34.2–35.9 E, the same box search_places ranks by), at least 10 m apart, and no
more than 100 km apart in a straight line. Each of those is refused as
invalid_input before any request is sent — the router's graph stops where the
map does, and a live call from Haifa into the sea was still unanswered after
40 seconds.
activity is a closed set of three, deliberately. Upstream's type= takes
Hike, Bike and 4WD, and answers anything else — a typo, a renamed
constant — with a walking route rather than an error. So this server sends
only words it knows, and then checks the profile upstream says it used against
the one asked for: a cycling request that comes back as a footpath is reported
as upstream_schema_changed rather than returned. The live test group exercises
that check on every activity, which is the only place it can be exercised.
None — upstream's fourth routing type, a straight line — is not offered. A
live call answers HTTP 500 (checked twice, 2026-08-15), and the map site's own
frontend never sends it either: it interpolates the straight line client-side.
Calling one a route would be the most misleading thing this server could return.
There is no ihmUrl: a calculated path is not a feature on the map site, and
this server creates nothing upstream to link to.
Known limitations
Things that are true of this server by design, and worth knowing before trusting an answer:
Everything is a mapped fact, not a current one. The data carries no observation dates. A trail may have closed, a spring dried, a track been fenced, at any point since somebody typed it in.
Only hiking routes are searchable. The same tiles carry cycling and 4x4 routes;
search_hiking_routesdoes not return them.Two of the map's sources resolve to geometry.
OSMandUsersdo;Nakeb,iNatureandWikidataappear in search results and are refused byget_route_detailswithunsupported_source. TheirihmUrlstill opens on the map site.Area searches are bounded by a tile budget, so a 40 km radius is the largest circle and a country-length route is too long a corridor to scan.
Long geometries are thinned, and a route still too detailed at 100 m is refused rather than truncated.
Names come in one language or the other, whichever the map data holds;
languageis a preference, not a translation.Nothing is cached across restarts. The cache is in memory, and a five minute TTL by default.
No elevation, no duration, no turn-by-turn. The routing endpoint can return instructions; this server does not ask for them.
Configuration
All settings are environment variables, read once at startup — an invalid value stops the server with a message naming the variable, rather than failing later inside a tool call.
Variable | Default | Range | Purpose |
|
| http(s) URL | API and tile host |
|
| http(s) URL | Where OSM route geometry is fetched from |
|
| 0 < x ≤ 60 | Applied to connect, read, write and pool |
|
| non-empty | Sent on every request |
|
| 0–86400 |
|
|
| ≥ 1 | Bounds the in-memory response cache |
|
| 1–16 | Simultaneous upstream connections |
|
| 1–500 | Tile budget for area searches |
|
| 1–64 | Request budget for nested OSM relations |
|
| log level | Logs go to stderr only |
Area searches and the tile budget
The map's routes and points of interest have no query API; they exist only as
the vector tiles the map site draws (/vector/data/global_points/{z}/{x}/{y}.mvt,
zoom 10–14). An area search therefore costs one request per tile covering it,
which grows with the square of the radius. Searches run at zoom 12 by
default, where a 40 km radius costs 98 tiles — just inside the default budget of
100. Only tiles that actually reach into the search circle are fetched; the box
around that circle would cost 121.
Zoom 12 was chosen for that budget and then checked for completeness: sampling zoom-12 tiles over Haifa, Jerusalem, Eilat and the Golan on 2026-08-14 against all sixteen of each tile's zoom-14 children found no features dropped at the lower zoom (817 features in the densest sample, 0 missing). The tileset is not thinned by zoom, so a zoom-12 search sees every marker a zoom-14 one would.
The same budget covers the corridor along a route, where the shape is a line rather than a circle and only the tiles the line itself comes near are fetched — the box around a route running diagonally holds more than twice as many.
Past the budget, a search fails with search_area_too_large naming the tile
count, the limit, and either a radius that would have worked or, for a route too
long for any buffer, that fact. It never silently returns part of the area.
Request behaviour
Every upstream request is a GET with a timeout, capped concurrency, and a short-lived in-memory cache. A request is retried once, and only after a timeout, a connection failure, or a 5xx; 4xx responses are never retried and failures are never cached. This is a personal-scale tool pointed at a volunteer-run service — please keep it that way.
Two hosts are contacted, each with its own connection pool and cache:
mapeak.com for search, tiles and shared routes, and api.openstreetmap.org
for OSM route geometry. Both see the same identifying User-Agent. OSM's
API usage policy applies
to the second, and one deeply nested relation is the only thing here that can
cost more than a handful of requests — hence its own budget above.
Error codes
Tool failures arrive as MCP errors whose text begins with a stable code:
invalid_input · place_not_found · route_not_found · unsupported_source ·
search_area_too_large · geometry_too_large · upstream_timeout ·
upstream_unavailable · upstream_schema_changed · rate_limited
upstream_timeout, upstream_unavailable and rate_limited are transient; the
rest will not be fixed by retrying. Upstream response bodies, URLs and
tracebacks are never included in the message — those go to the stderr log.
Acceptance run
The Haifa scenario, driven through a real MCP session against the live hosts on 2026-08-15. Abridged — warnings and attribution are on every response.
search_places "Haifa"
Haifa | Haifa, Haifa Subdistrict, Israel | /poi/OSM/node_1656107649
warning: 10 match(es) outside Israel were omitted.
search_hiking_routes 15 km around it, 4–12 km long
1.23 km OSM/relation_13363223 8.59 km Haifa Trail - Upper Hadar and Ramat Hadar
1.75 km Nakeb/255 7.5 km טיול מדרגות חיפה
5.21 km OSM/relation_20976850 5.87 km Connecting Paths
7.18 km Users/iXKu2M4BV5 6.46 km נחל גלים, כלח והמבצר האחרון
…
warning: Showing the 10 nearest of 16 matching routes.
get_route_details OSM/relation_13207704
Haifa Trail | Hiking | 903 positions, not thinned | MultiLineString
warning: recorded as 24 separate lines that do not meet end to end
get_route_details Users/iXKu2M4BV5
נחל גלים, כלח והמבצר האחרון | 6.46 km | +256 / −251 m | 538 positions
find_pois_along_route the Haifa Trail, 1,000 m, Water
120 m Water Well Vardiya Spring Well
615 m Waterfall מפל נחל הגיבורים
960 m Spring, Pond בריכת מעיין התאנה
warning: 3 of these are water features. Mapped water feature — not known to
be flowing, reachable, permitted or safe to drink. …
find_pois_along_route the same route, 500 m, default categories
106 m Natural Cave מערה כפולה
120 m Water Water Well Vardiya Spring Well
443 m Historic Memorial גדוד 22 חטיבת "כרמלי"
route_between_points 32.8191,34.9984 → 32.7800,35.0200 (straight line 4.79 km)
Hiking 6.39 km, 367 positions, ends snapped 11 m / 5 m
Bicycle 7.84 km, 391 positions, ends snapped 33 m / 5 m
4x4 8.01 km, 417 positions, ends snapped 33 m / 5 m
refusals
route_between_points into Cyprus → [invalid_input] outside the area this map covers
route_between_points Haifa → Eilat → [invalid_input] 364 km apart; routes up to 100 km
find_pois_along_route on the INT → [search_area_too_large] 128 tiles; a narrower
buffer would still need 119Two things the run showed that had already changed upstream since they were first measured: the Haifa Trail now resolves to 24 disconnected lines rather than the ten counted for its downtown section on 2026-08-14, and the Israel National Trail's corridor now costs 128 tiles rather than 123. Both are the mapping moving, not the server — and both are why the numbers in this README carry the date they were measured on.
Licensing and attribution
Read LICENSE-NOTICE.md in full before using any output. The short version:
Upstream map data is CC BY-NC-SA 3.0 (Israel Hiking Map / Mapeak) and ODbL (OpenStreetMap). The upstream licence states that all output of the work carries the same licence, so anything this server returns is non-commercial and share-alike.
Every response carries an
attributionobject naming both sources and their licences. Preserve it wherever the data is displayed or passed on. A model handed data with no provenance will invent some.This project is unofficial. It is not affiliated with, endorsed by, or supported by the Israel Hiking Map project or its maintainers.
This repository's own code is distributed under the same CC BY-NC-SA 3.0 terms, to keep the combined work unambiguous. The full legal text is in LICENSE.
Responsible use
Both hosts this server talks to are run for the public by people who are not being paid to serve it. Everything below is a deliberate constraint, not an accident of implementation:
Read-only. Every request is a GET. Nothing is written, no account is created, no session is held.
Identified. A descriptive User-Agent naming this project and its repository goes on every request to both hosts.
Bounded. Concurrency is capped, every request has a timeout, area searches have a tile budget and nested OSM relations have a request budget. A retry happens once, after a transient failure, never after a 4xx.
Cached. Responses are cached in memory for the session, so a repeated tool call in one conversation costs nothing upstream.
Before any public deployment, shared instance, or sustained automated querying: contact the Israel Hiking Map maintainers first, and read OpenStreetMap's API usage policy. A tool that makes it easy for a language model to fan out over somebody else's map tiles is exactly the kind of thing that gets an API closed for everybody.
And the point the whole design turns on: nothing here is a substitute for a current map, local knowledge, and carrying enough water. An answer from this server is a lead to check, not a plan to follow.
Available Tools
1 toolpingA
Check that the server is alive and report its version and data attribution.
This tool touches no upstream service. It is a placeholder used to verify transport and tool wiring, and will be removed once real tools exist.
| Name | Required | Description | Default |
|---|---|---|---|
| echo | No | pong |
Output Schema
| Name | Required | Description |
|---|---|---|
| echo | Yes | The caller's echo string, returned verbatim. |
| server | Yes | MCP server name. |
| status | Yes | Always 'ok' when the server is reachable. |
| version | Yes | Server version. |
| attribution | Yes | Required data attribution notice. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses key behavioral traits: it touches no upstream service, is a placeholder, and will be removed. No annotations are provided, so this is valuable. However, it doesn't explain the behavior of the echo parameter or detail the response beyond version/attribution, though an output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences: the first gives the core purpose, the second adds placeholder context. It is front-loaded and every sentence earns its place with no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple placeholder tool, the description covers purpose, safety, and lifecycle, but it omits any explanation of the echo parameter. Given the output schema likely covers return values, the description is mostly complete but not fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema defines an optional 'echo' parameter with a default but no description. The description does not mention this parameter at all, leaving its semantics entirely unspecified. With 0% schema coverage, this is a significant gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool checks server liveness and reports version/attribution, and explicitly labels it a placeholder for verifying transport/wiring. This is a specific verb+resource with clear scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says it is a placeholder for verifying transport and tool wiring, and notes it will be removed, which guides when to use it. It also states it touches no upstream service, implying it's safe for testing. No sibling alternatives exist, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
With only a single tool, there is no possibility of confusing it with other tools. The tool's purpose as a health check is clearly distinct.
The tool name 'ping' is a standard, recognizable term for a liveness check. While there is no pattern to compare against, the naming is unambiguous and follows common convention.
The server has only one placeholder tool, which is far too few for the domain implied by 'Israel Hiking MCP.' A single ping tool does not provide any substantive functionality.
The tool surface is severely incomplete. The server's purpose appears to be related to hiking, but no actual hiking tools exist; only a placeholder ping is provided, so there is no coverage of the domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
A basic MCP server to operate on the Postman API.
A simple MCP server built with FastMCP and python
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceA simple MCP server that can enable MCP clients to query Bluesky instances.34MIT
- AlicenseNot gradedqualityDmaintenanceAn experimental MCP server demonstrating remote calls via FastAPI, supporting ping-pong commands through API endpoints and SSE transport.2MIT
- FlicenseNot gradedqualityBmaintenanceA minimal MCP server for homelab environments, providing demo tools like ping and echo over Streamable HTTP for testing client-server integration.
- FlicenseNot gradedqualityDmaintenanceWork-in-progress MCP server that will provide travel guides and destination information from Wikivoyage via the MediaWiki API.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/tisheldev/israel-hiking-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server