viafrei 1.4.9 → 1.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +32 -8
- package/CHANGELOG.md +195 -0
- package/SOURCES.md +25 -18
- package/package.json +5 -1
package/API.md
CHANGED
|
@@ -9,7 +9,7 @@ the server's own text, reproduced verbatim, because that text is what an
|
|
|
9
9
|
assistant reads when it decides which tool to call; paraphrasing it here would
|
|
10
10
|
document a different server.
|
|
11
11
|
|
|
12
|
-
**It is a dated snapshot, taken on 2026-10-
|
|
12
|
+
**It is a dated snapshot, taken on 2026-10-02.** Generating this file makes
|
|
13
13
|
it impossible for the document and the snapshot to disagree — CI regenerates and
|
|
14
14
|
compares — but it cannot keep the snapshot from ageing against the live server,
|
|
15
15
|
because a capture is a point in time. **The source of truth is the running
|
|
@@ -17,12 +17,12 @@ server:** connect any MCP client and call `tools/list`.
|
|
|
17
17
|
|
|
18
18
|
| | |
|
|
19
19
|
| --- | --- |
|
|
20
|
-
| Server | `viafrei` 1.4
|
|
20
|
+
| Server | `viafrei` 1.5.4 |
|
|
21
21
|
| MCP protocol | `2025-06-18` |
|
|
22
22
|
| Streamable HTTP | https://mcp.viafrei.de/mcp |
|
|
23
23
|
| Legacy HTTP+SSE | https://mcp.viafrei.de/sse |
|
|
24
|
-
| Captured from | `https://mcp.viafrei.de/mcp` on 2026-10-
|
|
25
|
-
| Surface |
|
|
24
|
+
| Captured from | `https://mcp.viafrei.de/mcp` on 2026-10-02 |
|
|
25
|
+
| Surface | 20 tools, 10 resources, 2 resource templates, 9 prompts |
|
|
26
26
|
| Parameter schemas | JSON Schema draft-07 |
|
|
27
27
|
| Capabilities | `tools`, `resources`, `prompts`, `logging` |
|
|
28
28
|
|
|
@@ -31,7 +31,7 @@ No API key. No account. No sign-up.
|
|
|
31
31
|
## Contents
|
|
32
32
|
|
|
33
33
|
- [How to read a result](#how-to-read-a-result)
|
|
34
|
-
- [Tools](#tools) —
|
|
34
|
+
- [Tools](#tools) — 20
|
|
35
35
|
- [Resources](#resources) — 10
|
|
36
36
|
- [Resource templates](#resource-templates) — 2
|
|
37
37
|
- [Prompts](#prompts) — 9
|
|
@@ -410,7 +410,7 @@ The server's own instructions to a connecting client, verbatim:
|
|
|
410
410
|
|
|
411
411
|
**Read-only** — it changes nothing. Reaches a third-party source (open world). Idempotent: true. Destructive: false.
|
|
412
412
|
|
|
413
|
-
>
|
|
413
|
+
> Next departures from a German railway station, with platform, delay and cancellations. Use when asked when a train, S-Bahn or ICE leaves a named station, or whether THAT departure is late; vague later-today wording ("heute Abend") stays here. Whether ONE line is punctual ("ist die S1 pünktlich?") is NOT this tool, though it is rail and about delay — call check_transit_disruption. Do NOT use for buses, trams, a non-railway stop, another day or a time over 2 h away — get_departures. No destination filter: read the board. Max 15 departures, window 120 min. Results carry their attribution line.
|
|
414
414
|
|
|
415
415
|
| parameter | type | required | default | constraints |
|
|
416
416
|
| --- | --- | --- | --- | --- |
|
|
@@ -425,9 +425,33 @@ The server's own instructions to a connecting client, verbatim:
|
|
|
425
425
|
- **`eva_no`** — The station's EVA number (6–8 digits, e.g. 8002549 for Hamburg Hbf), when a previous result gave you one. It skips the name lookup and is exact — use it to answer a follow-up about a station this tool has already named.
|
|
426
426
|
- **`language`** — Set this on every call to the language the person is writing in: "en" if they wrote English, "de" if they wrote German. Do not leave it out because it has a default — the default is only the fallback when the language is genuinely unclear, and an English question answered in German is a wrong answer. Place names, station names and road numbers are never translated in either language; in English the German term is kept in parentheses so the person recognises it on signs and in local apps.
|
|
427
427
|
- **`limit`** — How many departures to return, earliest first (1–15, default 10). More than 15 is refused — that is a board a person can read, not a dataset.
|
|
428
|
-
- **`station`** — The railway station, as the person says it: "Hamburg Hbf", "Köln Hbf", "Munich Central", "Frankfurt (Main) Hbf". Pass their words — English names and "central station" are understood. If the name fits several stations the result lists them and asks which; do not guess one yourself. Give either station OR eva_no, never both.
|
|
428
|
+
- **`station`** — The railway station, as the person says it: "Hamburg Hbf", "Köln Hbf", "Munich Central", "Frankfurt (Main) Hbf". Pass their words — English names and "central station" are understood. If the name fits several stations (a bare "Hauptbahnhof"), call anyway: the result lists them and asks which; do not guess one yourself. Give either station OR eva_no, never both.
|
|
429
429
|
- **`when`** — Start of the window as an ISO-8601 instant with an offset ("2026-09-20T18:30:00+02:00"). Leave it out for "now", which is what almost every question means. Times in the answer are Europe/Berlin whatever you pass.
|
|
430
430
|
|
|
431
|
+
### `get_departures` — Scheduled departures (bus, tram, train)
|
|
432
|
+
|
|
433
|
+
**Read-only** — it changes nothing. Answers from data this service already holds (closed world). Idempotent: true. Destructive: false.
|
|
434
|
+
|
|
435
|
+
> Scheduled departures from any German public-transport stop — bus, tram, U-Bahn, S-Bahn, train, ferry — with line, destination, platform. Use when someone asks when a bus, tram, U-Bahn or ferry goes, or for another DAY or a clock time over 2 h away: "Wann fährt der nächste Bus ab Fulda Bahnhof?" Do NOT use for a railway station's trains now or later today — get_train_departures. Planned times only: for "is my bus late?" give the plan and say so; regional punctuality check_transit_disruption. No destination filter: read the board. Window 48 h, 15 per call. Results carry their attribution line.
|
|
436
|
+
|
|
437
|
+
| parameter | type | required | default | constraints |
|
|
438
|
+
| --- | --- | --- | --- | --- |
|
|
439
|
+
| `duration_min` | integer | no | `60` | min 5; max 1440 |
|
|
440
|
+
| `language` | string | no | `"de"` | one of `"de"`, `"en"` |
|
|
441
|
+
| `limit` | integer | no | `10` | min 1; max 15 |
|
|
442
|
+
| `modes` | array of string | no | — | min 1 item(s); each item: one of `"rail"`, `"subway"`, `"tram"`, `"bus"`, `"ferry"` |
|
|
443
|
+
| `stop` | string | no | — | min length 2 |
|
|
444
|
+
| `stop_id` | string | no | — | min length 3 |
|
|
445
|
+
| `when` | string | no | — | format `date-time`; pattern (288 characters — see the description; the `format` above is the short answer) |
|
|
446
|
+
|
|
447
|
+
- **`duration_min`** — How far past that moment to look, in minutes (5–1440, default 60). Small for "what goes now", a few hours for an evening. To reach the far end of the 48 h timetable, move `when` instead of widening this: a window of a whole day returns at most 15 rows and would answer about the wrong half of it.
|
|
448
|
+
- **`language`** — Set this on every call to the language the person is writing in: "en" if they wrote English, "de" if they wrote German. Do not leave it out because it has a default — the default is only the fallback when the language is genuinely unclear, and an English question answered in German is a wrong answer. Place names, station names and road numbers are never translated in either language; in English the German term is kept in parentheses so the person recognises it on signs and in local apps.
|
|
449
|
+
- **`limit`** — How many departures to return, earliest first (1–15, default 10). The result always says how many more were in the window.
|
|
450
|
+
- **`modes`** — Keep only these kinds of service: "bus", "tram", "subway" (U-Bahn), "rail" (every train, including S-Bahn and regional) or "ferry". Omit it unless the person named a kind — "nur Busse", "welche Tram". Several are allowed, which is what "die Busse und Bahnen vor dem Hbf" means. An S-Bahn is "rail": the feed does not always distinguish it, and the line name ("S 6") says which it is.
|
|
451
|
+
- **`stop`** — The stop, as the person says it: "Fulda, Bahnhof", "München, Marienplatz", "Köln, Hbf", "Hamburg, Rathausmarkt" (town first). Include the town when the person did — half the names in Germany exist in twenty towns, and a bare "Bahnhof" or "Hauptbahnhof" comes back as a list of candidates to choose from, so call it and let the result ask. Pass their words; do not guess an id. Give either stop OR the stop id, never both.
|
|
452
|
+
- **`stop_id`** — The stop's timetable id, exactly as a previous result of this tool gave it ("de:06631:1234"). It skips the name lookup and is exact — use it for a follow-up about a stop this tool has already named, and for one the person picked out of a candidate list.
|
|
453
|
+
- **`when`** — Start of the window as an ISO-8601 instant with an offset ("2026-10-02T07:30:00+02:00"). Leave it out for "now". Convert the person's words yourself — "morgen früh", "tonight" — and pass the instant; the answer is always rendered in Europe/Berlin.
|
|
454
|
+
|
|
431
455
|
### `check_station_facilities` — Station lifts and escalators
|
|
432
456
|
|
|
433
457
|
**Read-only** — it changes nothing. Reaches a third-party source (open world). Idempotent: true. Destructive: false.
|
|
@@ -655,5 +679,5 @@ single call.
|
|
|
655
679
|
---
|
|
656
680
|
|
|
657
681
|
Generated from `catalogue.json` by `scripts/gen-api-doc.mjs`. The snapshot was
|
|
658
|
-
read from `https://mcp.viafrei.de/mcp` on 2026-10-
|
|
682
|
+
read from `https://mcp.viafrei.de/mcp` on 2026-10-02; no tool was invoked to
|
|
659
683
|
produce it, so no data provider was contacted.
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,200 @@ a Changelog and the versions follow Semantic Versioning.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.5.4] - 2026-10-02
|
|
9
|
+
|
|
10
|
+
**Mirrors the server.** The bridge is versioned to match the ViaFrei MCP server it
|
|
11
|
+
relays to. The running server reports 1.5.4 while the registry's latest is 1.4.9, so
|
|
12
|
+
this release moves the package to the server's number and carries whatever had been
|
|
13
|
+
waiting under `[Unreleased]`. Prepared by the `Version sync` workflow: the shipped
|
|
14
|
+
reference was re-captured from the running server, and the probe reported the surface
|
|
15
|
+
**CHANGED** — the automation knows what moved, not what it means:
|
|
16
|
+
|
|
17
|
+
- tools: the server has get_departures, the snapshot does not
|
|
18
|
+
- tools: get_train_departures differs between the server and the snapshot
|
|
19
|
+
|
|
20
|
+
What that means, written by a person after reading the diff and asking the server:
|
|
21
|
+
|
|
22
|
+
- **`get_departures` is new**: scheduled departures from any German public-transport
|
|
23
|
+
stop — bus, tram, U-Bahn, S-Bahn, train, ferry — with line, destination and
|
|
24
|
+
platform, planned times only, a 48 h window and 15 per call, answering from the
|
|
25
|
+
DELFI static timetable (CC BY 4.0). It is the tool for "when does the next bus go",
|
|
26
|
+
for another day, or for a clock time more than two hours away. Asked on 2026-10-02,
|
|
27
|
+
prod answered that the timetable is **not loaded yet** and said so plainly instead
|
|
28
|
+
of inventing a board; `SOURCES.md` records that on the static-GTFS row rather than
|
|
29
|
+
promoting the source to *live*.
|
|
30
|
+
- **`get_train_departures` was re-described, not re-shaped**: its description now
|
|
31
|
+
draws the line against the new tool (buses, trams, a non-railway stop, another day
|
|
32
|
+
or a time over two hours away go to `get_departures`), keeps vague later-today
|
|
33
|
+
wording for itself, and sends "is the S1 punctual?" to `check_transit_disruption`
|
|
34
|
+
even though it is rail and about delay. The `station` argument's text adds that a
|
|
35
|
+
bare "Hauptbahnhof" should be sent as-is because the server lists the candidates.
|
|
36
|
+
No argument was added, removed or re-typed.
|
|
37
|
+
- The catalogue is **20 tools, 18 read-only**; `SOURCES.md` moves from nineteen /
|
|
38
|
+
seventeen to those numbers, and the live calls a re-measurement would cost from
|
|
39
|
+
fifteen to sixteen, because the tool gained is read-only and not fuel.
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- **A scheduled freshness probe: is the service alive, not merely answering?**
|
|
44
|
+
(`scripts/probe-freshness.mjs`, `npm run probe:freshness`, and the `Freshness`
|
|
45
|
+
workflow every six hours.)
|
|
46
|
+
|
|
47
|
+
The gap it closes was real and nothing here could see it. A server can return
|
|
48
|
+
`200` with a correctly shaped body for days while an ingest worker is dead, and
|
|
49
|
+
every existing check survives that: the stub tests prove the bridge's
|
|
50
|
+
**transport**, `check:docs` proves the document matches the **snapshot**, and the
|
|
51
|
+
cut-time probe proves the **surface** still matches. None of them reads the age
|
|
52
|
+
of the data in an answer.
|
|
53
|
+
|
|
54
|
+
This asks the running server and judges `_meta.asOf`, which every real-time tool
|
|
55
|
+
carries, against a limit **per tool**. That is not a detail: measured against
|
|
56
|
+
prod on 2026-10-01, autobahn, transit, weather and departures all answered within
|
|
57
|
+
a minute while `check_road_status` was **7.5 h** old, because it blends the BASt
|
|
58
|
+
roadworks feed, which the Mobilithek catalogue declares as **twice daily**. One
|
|
59
|
+
global limit would be either useless for the fast feeds or permanently red for the
|
|
60
|
+
slow one — and a check that is permanently red is a check that gets switched off.
|
|
61
|
+
|
|
62
|
+
Each limit sits about an order of magnitude above the source's own **declared
|
|
63
|
+
cadence** rather than above the single reading this was written against, so it
|
|
64
|
+
catches a dead worker and cannot fire on normal variation. 72 h for roadworks is
|
|
65
|
+
roughly six times a twice-daily interval and clears a weekend; 90 min for the
|
|
66
|
+
other four is many times their providers' own floors.
|
|
67
|
+
|
|
68
|
+
**The callable set is an allow-list, not a deny-rule**, and the direction is the
|
|
69
|
+
point: with a deny-rule a new entry runs unless it matches, and here the failure
|
|
70
|
+
mode is a licence breach against a provider that can revoke access. Fail-closed is
|
|
71
|
+
the right default on that path, so a tool nobody named is refused.
|
|
72
|
+
|
|
73
|
+
**No fuel tool is ever called**, stated separately because it carries the reason
|
|
74
|
+
the allow-list does not: `find_cheapest_fuel` and `find_fuel_station` answer from
|
|
75
|
+
MTS-K / Tankerkönig, which sets a minimum interval per station and limits use to
|
|
76
|
+
answering a consumer's question. A monitoring query is not that. Both guards
|
|
77
|
+
**refuse before any request**, and the fuel arm is not redundant — a self-test
|
|
78
|
+
case adds a fuel tool to **both** lists, which is the realistic way the exclusion
|
|
79
|
+
would be lost, and it is still refused on licence grounds.
|
|
80
|
+
|
|
81
|
+
**Scheduled, not on push**, because CI here reaches nothing by design: a
|
|
82
|
+
freshness failure is news about the service, not about the commit, and reddening
|
|
83
|
+
a contributor's push for it would teach people to ignore red.
|
|
84
|
+
|
|
85
|
+
**The instrument is proved before it is trusted**, and the workflow runs the two
|
|
86
|
+
steps in that order. The self-test is hermetic — every case against a local stub
|
|
87
|
+
on loopback — and it is the only place the staleness verdict is ever exercised,
|
|
88
|
+
because a healthy endpoint cannot produce a stale payload. So the self-test runs
|
|
89
|
+
**first**: if it fails the instrument is broken, and if the live step fails the
|
|
90
|
+
service is. A monitor whose verdict is never proved reports success about a dead
|
|
91
|
+
service exactly as convincingly as about a live one.
|
|
92
|
+
|
|
93
|
+
Three exit codes, because "could not check" and "checked and it is wrong" are
|
|
94
|
+
different answers: `0` every feed inside its limit, `1` a real defect (stale, or
|
|
95
|
+
no `asOf`, or no attribution, or `isError`, or an `asOf` in the future — a clock
|
|
96
|
+
fault must not read as very fresh), and `2` could not check (endpoint, session,
|
|
97
|
+
or a response shape nobody recognises). An unparsable body is deliberately `2`
|
|
98
|
+
rather than `1`.
|
|
99
|
+
|
|
100
|
+
Found by its own self-test and fixed: `--json` printed the human summary to
|
|
101
|
+
stdout after the document, so the stream did not parse. Both streams are now
|
|
102
|
+
pinned by a case.
|
|
103
|
+
|
|
104
|
+
**Found in review, and it is the case the first draft had no test for.** A
|
|
105
|
+
JSON-RPC *error* — what the server returns for a retired tool or a renamed
|
|
106
|
+
argument, and this watch list hard-codes seven argument names — fell through to
|
|
107
|
+
the no-result branch: **exit 1, every feed printed `STALE`, on a healthy
|
|
108
|
+
service**, and `error.message`, the entire diagnosis, discarded. It is now exit
|
|
109
|
+
**2** with the server's code and message printed, a distinct `?????` label
|
|
110
|
+
because `STALE` is a claim about the *data* rather than about our ability to
|
|
111
|
+
measure it, and a refusal sentence that no longer says the body failed to parse —
|
|
112
|
+
it parsed perfectly. Four assertions cover it, and removing the guard turns all
|
|
113
|
+
four red.
|
|
114
|
+
|
|
115
|
+
- **The registry is compared with the server every six hours, and a release that
|
|
116
|
+
would close the gap is PREPARED — never performed** (`scripts/propose-release.mjs`,
|
|
117
|
+
`npm run propose:release`, and the `Version sync` workflow).
|
|
118
|
+
|
|
119
|
+
The bridge is versioned to match the server it relays to, and until now the only
|
|
120
|
+
thing that noticed the registry falling behind was a person checking by hand: 1.4.9
|
|
121
|
+
sat on prod while npm said 1.4.8 until somebody asked. Every step of catching up
|
|
122
|
+
was mechanical and identical each time — `npm version`, the probe's `--write`,
|
|
123
|
+
`docs:api`, the `## [X.Y.Z]` block, the gates — so the workflow does them and
|
|
124
|
+
pushes the result as `release/X.Y.Z` with a pull request.
|
|
125
|
+
|
|
126
|
+
**What it will not do, by design.** It does not merge, tag or publish, for three
|
|
127
|
+
reasons each sufficient alone: the merge needs a reviewer verdict covering HEAD,
|
|
128
|
+
which a bot merging through the API would bypass; an npm version is immutable, so
|
|
129
|
+
a wrong one is forever; and when the server's **surface** changed rather than its
|
|
130
|
+
number, the release note needs a sentence about what the change means, which
|
|
131
|
+
nothing here can write — the 1.4.9 cut carried a licence-relevant fix for exactly
|
|
132
|
+
that case. So the verdict, the merge and the tag stay with a person, and the tag
|
|
133
|
+
publishes as it always has.
|
|
134
|
+
|
|
135
|
+
**Four states, each named in the output**, because the workflow branches on them:
|
|
136
|
+
`in-sync`, `awaiting-tag` (main already carries the server's version; the tag is
|
|
137
|
+
the missing step), `drift` (the one that is prepared), and `behind` — the server
|
|
138
|
+
BEHIND the registry, which is exit 1 and proposes nothing, because a downgrade is
|
|
139
|
+
a decision about whether prod rolled back or a publish was premature.
|
|
140
|
+
|
|
141
|
+
**Every version string read from the network is checked against `X.Y.Z` before it
|
|
142
|
+
is used anywhere**, since it ends up in a branch name, a commit and an `npm
|
|
143
|
+
version` argument; a prerelease on either side is a refusal. A mutant with the
|
|
144
|
+
guard removed is part of the self-test, so the guard is proved live rather than
|
|
145
|
+
present. Detect **writes nothing**, asserted by hashing the five files it may
|
|
146
|
+
later touch. The server is read through the catalogue probe — one reader of that
|
|
147
|
+
endpoint, `initialize` and the four list calls, no tool invoked — and the probe's
|
|
148
|
+
own WRONG/DATED verdict decides the lead of the CHANGELOG block: DATED says the
|
|
149
|
+
surface is unchanged; WRONG lists what moved and says **a person must describe it
|
|
150
|
+
before this merges**, and the pull request is opened as a **draft**. A failing
|
|
151
|
+
offline gate is also a draft rather than a lost run: the gate's output goes into
|
|
152
|
+
the pull request, where the person who has to act on it will read it.
|
|
153
|
+
|
|
154
|
+
A proposal is idempotent across runs — a `release/X.Y.Z` branch already on origin
|
|
155
|
+
is left alone, so a pull request waiting for its review is not joined by a twin
|
|
156
|
+
every six hours — and a CHANGELOG already carrying the block is a refusal. The
|
|
157
|
+
workflow dispatches CI on the branch explicitly, because a push or a pull request
|
|
158
|
+
made with the workflow token starts no workflow by GitHub's rule. **Two
|
|
159
|
+
preconditions are asserted before anything is read**, because each failure would
|
|
160
|
+
otherwise conceal itself: the run must be on the default branch (a dispatch from
|
|
161
|
+
another ref would branch off it and open a pull request carrying its commits), and
|
|
162
|
+
the repository must allow Actions to open pull requests — a setting that is OFF by
|
|
163
|
+
default (and was, here, until 2026-10-02), without which `gh pr create` fails after
|
|
164
|
+
the branch is pushed and the orphan branch then silences every later run. That
|
|
165
|
+
read is administration-class and the workflow token may not be able to make it,
|
|
166
|
+
so it has **three outcomes**: a successful `false` refuses, a failed read is named
|
|
167
|
+
and the run continues, because if the pull request still cannot be opened the
|
|
168
|
+
branch just pushed is deleted again for the same reason.
|
|
169
|
+
|
|
170
|
+
The MCP stub the catalogue probe's self-test ran on moved to `scripts/mcp-stub.mjs`,
|
|
171
|
+
and the pass/fail counter both self-tests print through to `scripts/check-harness.mjs`,
|
|
172
|
+
so this self-test shares them rather than carrying copies; the probe's own case
|
|
173
|
+
count is unchanged.
|
|
174
|
+
|
|
175
|
+
### Fixed
|
|
176
|
+
|
|
177
|
+
- **The `Version sync` workflow runs the leak sweep on the tree it prepares.** Its
|
|
178
|
+
first real run was this release, and the proposal it pushed carried two bare
|
|
179
|
+
numbers from the new tool's schema text — a minutes-per-day maximum and an example
|
|
180
|
+
stop id — that the public-repo sweep refuses. Nothing in the workflow had asked:
|
|
181
|
+
its three gates compare the shipped files with each other, not whether the
|
|
182
|
+
snapshot may be published. What caught it was the CI run the workflow itself
|
|
183
|
+
dispatched — the pull request's own `pull_request` run never executed, it sat at
|
|
184
|
+
`action_required` — and the step that failed was the publish-hygiene gate on the
|
|
185
|
+
**built tarball**, because `API.md` ships in the package: the numbers were on their
|
|
186
|
+
way into the published artefact, not only into the repository. The sweep now runs
|
|
187
|
+
after the five files are staged, and a finding makes the proposal a **draft** with
|
|
188
|
+
the findings in the pull-request body. That job builds nothing, so it cannot run
|
|
189
|
+
the tarball gate itself: it covers this class of finding, not the exact gate that
|
|
190
|
+
fired. The two numbers are on `numbers.allowed` as the harmless values they are;
|
|
191
|
+
both exist only in text the server controls, so a re-wording upstream makes the
|
|
192
|
+
sweep refuse them as unused — loudly, which is the right direction.
|
|
193
|
+
- **`check-sources`' self-test reads its counts off the check's own summary line**
|
|
194
|
+
instead of carrying them: three of its cases said "seventeen" and "fifteen", and
|
|
195
|
+
when the page correctly moved to eighteen and sixteen they went inert — one passed
|
|
196
|
+
without mutating anything — or asserted the previous release's numbers. A mutation
|
|
197
|
+
that changes nothing, or that would change one of two occurrences, is now a
|
|
198
|
+
refusal. The check's own pattern for the re-run sentence accepts "would now mean"
|
|
199
|
+
beside "would still mean", because the count did move this time and the page says
|
|
200
|
+
so.
|
|
201
|
+
|
|
8
202
|
## [1.4.9] - 2026-10-01
|
|
9
203
|
|
|
10
204
|
**Mirrors the server.** The bridge is versioned to match the ViaFrei MCP server
|
|
@@ -1451,6 +1645,7 @@ for it, so the number is free; the bridge will use it when the platform does.
|
|
|
1451
1645
|
commits, and a squash makes them unreachable from `main` - which would turn
|
|
1452
1646
|
the check red on `main` for everybody, for something no contributor did.
|
|
1453
1647
|
|
|
1648
|
+
[1.5.4]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.5.4
|
|
1454
1649
|
[1.4.9]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.4.9
|
|
1455
1650
|
[1.3.22]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.22
|
|
1456
1651
|
[1.3.16]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.16
|
package/SOURCES.md
CHANGED
|
@@ -143,28 +143,35 @@ is deliberately not re-measured, and the count says so rather than absorbing it:
|
|
|
143
143
|
status this page cannot stand behind is worse than an honest gap.
|
|
144
144
|
|
|
145
145
|
**The server has grown since that measurement, and this page has not re-run it.**
|
|
146
|
-
As of the 2026-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
`
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
not one.**
|
|
146
|
+
As of the 2026-10-02 capture shipped alongside this page it exposes twenty tools,
|
|
147
|
+
eighteen of them read-only. Between that measurement and the 2026-10-02 capture it
|
|
148
|
+
gained two tools, and both matter here. One is a SECOND fuel tool,
|
|
149
|
+
`find_fuel_station`, excluded from any spot check for exactly the same reason
|
|
150
|
+
`find_cheapest_fuel` is, and the reason is a licence condition rather than a
|
|
151
|
+
convenience: MTS-K sets a minimum interval per station and its terms make needless
|
|
152
|
+
querying a real risk to the access itself. **Both fuel tools are excluded, not one.**
|
|
153
|
+
The other is `get_departures` (server 1.5.4): scheduled departures from any
|
|
154
|
+
public-transport stop, answering from the DELFI static timetable — a source this
|
|
155
|
+
page had listed as *read* with nothing using it. Something uses it now, and on
|
|
156
|
+
2026-10-02 the server's own answer was that the timetable is not loaded yet; the row
|
|
157
|
+
below says exactly that rather than promoting it.
|
|
153
158
|
|
|
154
159
|
The sentence above therefore describes what was measured on 2026-09-27 and not what
|
|
155
|
-
the server offers today. Re-running it would
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
avoid.
|
|
160
|
+
the server offers today. Re-running it would now mean **sixteen** live calls against
|
|
161
|
+
real providers: the read-only tools minus the two excluded fuel tools. The count moved
|
|
162
|
+
by one because `get_departures` is read-only and not fuel, so a re-run would call
|
|
163
|
+
it. Those calls would mostly re-confirm statuses this page already knows, so it is
|
|
164
|
+
dated on purpose rather than refreshed on a schedule — and dated is said out loud,
|
|
165
|
+
because a measurement silently carried forward under a present-tense sentence is the
|
|
166
|
+
failure this section exists to avoid.
|
|
163
167
|
|
|
164
168
|
- **live** — an answer came back naming it when this page was checked;
|
|
165
169
|
- **in the service** — licensed and loaded, and the spot check produced no
|
|
166
170
|
answer that named it, so it is reported as unconfirmed rather than as live;
|
|
167
|
-
- **read** — the licence is read and cleared, and
|
|
171
|
+
- **read** — the licence is read and cleared, and no answer has been seen from it:
|
|
172
|
+
because nothing asks it, because what asks it is told the data is not loaded, or
|
|
173
|
+
because what asks it has not been seen to get an answer either way. Where it is not
|
|
174
|
+
simply that nothing asks it, the row says so.
|
|
168
175
|
|
|
169
176
|
There used to be a fourth value, **not on the public service today**, and no row
|
|
170
177
|
carries it any more: the three rows that did now answer. It is removed from this
|
|
@@ -188,8 +195,8 @@ status somebody could still be relying on.
|
|
|
188
195
|
| Public-transport realtime (GTFS-RT Trip Updates) | DELFI e.V., via the national access point (Mobilithek) | Germany-wide departure and arrival forecasts | real time | **CC BY-SA (version unstated)** | live |
|
|
189
196
|
| FaSta — Facility Status | Deutsche Bahn AG (DB API Marketplace) | Live state of lifts and escalators at stations | live status | CC BY 4.0 | live |
|
|
190
197
|
| Geocoding (addresses and points of interest) | OpenStreetMap contributors | Street and house-number points and mapped points of interest in Germany | refreshed from the OSM extract | **ODbL 1.0** | live |
|
|
191
|
-
| Timetable data (static GTFS) | DELFI e.V. | Germany-wide scheduled public transport | weekly release | CC BY 4.0 | read |
|
|
192
|
-
| Stop directory (zHV) | DELFI e.V. | Every public-transport stop in Germany with its identifier and coordinates | weekly release | CC BY 4.0 | read |
|
|
198
|
+
| Timetable data (static GTFS) | DELFI e.V. | Germany-wide scheduled public transport | weekly release | CC BY 4.0 | read — asked by `get_departures` since server 1.5.4; on 2026-10-02 the server answered that the timetable is not loaded yet, and said so rather than inventing a board |
|
|
199
|
+
| Stop directory (zHV) | DELFI e.V. | Every public-transport stop in Germany with its identifier and coordinates | weekly release | CC BY 4.0 | read — `get_departures` resolves stop names against it since server 1.5.4; the 2026-10-02 answer named no stop and said only that the timetable is not loaded, so whether the directory answered cannot be read off it |
|
|
193
200
|
| Disruption reports (Störungsmeldungen) | DELFI e.V., via the national access point (Mobilithek) | Germany-wide public-transport disruption messages | real time | **CC BY-SA 4.0** | read |
|
|
194
201
|
| Station car parks (DB BahnPark) | Deutsche Bahn AG (DB API Marketplace) | Car parks at railway stations, with their operator and access details | continuous | **dl-de/by-2-0** | read |
|
|
195
202
|
| Administrative units and place names | Bundesamt für Kartographie und Geodäsie (BKG), product GN250 | Länder, Regierungsbezirke, Kreise, Gemeinden with their official keys and names | yearly release | **dl-de/by-2-0** | live |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viafrei",
|
|
3
|
-
"version": "1.4
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "German traffic, rail, parking, charging, fuel, address and weather data in your AI assistant - MCP, no API key. stdio bridge to the hosted ViaFrei MCP server.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -79,6 +79,10 @@
|
|
|
79
79
|
"test:sources": "node scripts/check-sources.test.mjs",
|
|
80
80
|
"probe:catalogue": "node scripts/probe-catalogue.mjs",
|
|
81
81
|
"test:probe": "node scripts/probe-catalogue.test.mjs",
|
|
82
|
+
"probe:freshness": "node scripts/probe-freshness.mjs",
|
|
83
|
+
"test:freshness": "node scripts/probe-freshness.test.mjs",
|
|
84
|
+
"propose:release": "node scripts/propose-release.mjs",
|
|
85
|
+
"test:propose": "node scripts/propose-release.test.mjs",
|
|
82
86
|
"rules:show": "node scripts/show-rules.mjs"
|
|
83
87
|
},
|
|
84
88
|
"dependencies": {
|