Atlas / MCP servers / mikkoparkkola / Trvl

TrvlBLOCK

mcp/mikkoparkkola/trvl

Travel MCP server + CLI for AI assistants — flights, hotels, trains, cars, ferries, price alerts. No API keys, single Go binary. 1 smart MCP tool + 66 aliases (98.9% smaller tools/list). Works with Claude, Cursor, Windsurf, Codex.

Verdict
BLOCK
Grade
F
Trust score
55 /100
Exposed tools
—
Transport
stdio
License
NOASSERTION
Stars
86
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://goreportcard.com/report/github.com/MikkoParkkola/trvl) [](https://github.com/MikkoParkkola/trvl/actions/workflows/ci.yaml) [](https://github.com/MikkoParkkola/trvl/releases) [](https://github.com/MikkoParkkola/trvl/releases) [](LICENSE) [](https://pkg.go.dev/github.com/MikkoParkkola/trvl) [](https://modelcontextprotocol.io/specification/2026-07-28) [](https://github.com/MikkoParkkola/trvl#what-it-can-do) [](https://go.dev/) [](https://insiders.vscode.dev/redirect/mcp/install?name=trvl&config=%7B%22command%22%3A%22trvl%22%2C%22args%22%3A%5B%22mcp%22%5D%7D) [](cursor://anysphere.cursor-deeplink/mcp/install?name=trvl&config=%7B%22command%22%3A%22trvl%22%2C%22args%22%3A%5B%22mcp%22%5D%7D) [](https://socialistic.ai/en/skill/trvl-travel-mcp-4f7aa7)

Ask your AI assistant to plan a real trip, and it actually can. trvl gives Claude, Cursor, Windsurf, Codex, or any MCP-compatible cli

Read from source at commit 74b0aee82db1OBSERVED · 2026-10-08
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (oci)
claude mcp add trvl:1.26.0 --env TRVL_MCP_TOKEN=${TRVL_MCP_TOKEN} --env TRVL_MCP_READ_TOKEN=${TRVL_MCP_READ_TOKEN} --env TRVL_MCP_WRITE_TOKEN=${TRVL_MCP_WRITE_TOKEN} --env TRVL_MCP_OAUTH_CLIENT_SECRET=${TRVL_MCP_OAUTH_CLIENT_SECRET} -- docker run -i --rm ghcr.io/mikkoparkkola/trvl:1.26.0:None
claude-code (npm)
claude mcp add trvl-mcp --env TRVL_MCP_TOKEN=${TRVL_MCP_TOKEN} --env TRVL_MCP_READ_TOKEN=${TRVL_MCP_READ_TOKEN} --env TRVL_MCP_WRITE_TOKEN=${TRVL_MCP_WRITE_TOKEN} --env TRVL_MCP_OAUTH_CLIENT_SECRET=${TRVL_MCP_OAUTH_CLIENT_SECRET} -- npx -y [email protected]
03

Trust audit

BLOCKgrade F · trust 55/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (5 observation(s))
Network
declared (5 observation(s))
Shell
declared (5 observation(s))
Dependencies
pinned
Secrets in source
found

Findings (25)

HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
internal/calendarbusy/calendarbusy.go:57
if out, err := exec(ctx, "gws", "calendar", "agenda", "--days", itoa(days), "--format", "json"); err == nil {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
internal/calendarbusy/calendarbusy.go:60
if out, err := exec(ctx, "icalBuddy", "-f", "-n", "-ea", "-nc", "-b", "", "-iep", "title,datetime", "-po", "title,datetime", "eventsFrom:today", "to:today+"+itoa(days)); err == nil {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
MEDIUMObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
internal/selfupdate/keys/mldsa65_v1.pubkey.hex:1
05281eded06cc2ab73ce99b9e42369ec3bd16638c8ec1453c4a95c51ee0e5c0ff13a4a81346a477b7a2beafa0b8fa028f37e7d0371709333053f7b12583b51bc6af2cf3246b6a09819fb93732124686523d61f945bc18069aaea5e5cd88add90af306407
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
internal/watch/webhook_log_test.go:48
const secret = "T00000000-B11111111-zzzzzzzzzzzzzzzzzzzzzzzz"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
internal/watch/webhook_log_test.go:86
const secret = "T00000000-B11111111-yyyyyyyyyyyyyyyyyyyyyyyy"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
mcp/watch_price_response_test.go:77
const token = "T4K9m2QpR7vN1sW6xL8b"
LOWInventory / provenance · inv.hidden_file · CWE-1104
.goreleaser.yaml
.goreleaser.yaml
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.trivyignore
.trivyignore
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
docs/.nojekyll
.nojekyll
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
cmd/trvl/import_inbox_test.go:15
const fixtureDir = "../../internal/inboxparser/testdata"
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
internal/flights/policy_test.go:139
"CLI": "../../cmd/trvl/flights.go",
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
internal/flights/policy_test.go:140
"MCP": "../../mcp/tools_flights.go",
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
internal/ground/policy_test.go:27
"CLI": "../../cmd/trvl/ground.go",
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
internal/ground/policy_test.go:28
"MCP": "../../mcp/tools_ground.go",
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
internal/cookies/header_origin_test.go:41
{"link local metadata ip", "https://169.254.169.254/latest/meta-data/", false},
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
internal/hotels/booking_rooms_origin_test.go:29
"http://169.254.169.254/latest/meta-data/",
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
internal/hotels/booking_rooms_refusal_test.go:34
opts.BookingURL = "http://169.254.169.254/latest/meta-data/"
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
internal/providers/cookies_test.go:561
{"link-local metadata", endpoint, "http://169.254.169.254/latest/meta-data/", false},
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
internal/providers/cookies_test.go:576
{"self-hosted endpoint, metadata service", "http://127.0.0.1:8080/api", "http://169.254.169.254/latest/meta-data/", false},
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
CHANGELOG.md:662
- **`/dashboard` is now browser-native on localhost.** A loopback bind serves the dashboard without a bearer token (read-only, secret-redacted, local-only — the same posture as `/health`), so `trvl mc
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
cmd/trvl-telemetry/README.md:50
`http://127.0.0.1:8080/v1/heartbeat`. The path the binary serves is
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/CLI.md:22
When running as an HTTP server (`trvl mcp --http`), the same view is served as a read-only, auto-refreshing HTML dashboard at `/dashboard`. On a local (loopback) bind it needs no token — just open <ht
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/REMOTE-MCP-OAUTH.md:106
`http://localhost`/`http://127.0.0.1` is allowed for local development only).
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/design/oauth-protected-resource-metadata.md:94
- **Exception:** `http://localhost` and `http://127.0.0.1` public URLs are
LOWObfuscation / stealth · obf.base64_blob · CWE-506, CWE-94
internal/ground/testdata/rome2rio_london_paris.html:516
<!--F/--></span><!--F/--></button></div><!--M/--><!--M#s0-2-0-20-37-6-49-3[2]--><div aria-labelledby="s0-2-0-20-37-6-49-3[2]-@0" class="mt-6"><div id="s0-2-0-20-37-6-49-3[2]-@0" class="px-4 pb-2 text-

Gates applied: no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha 74b0aee82db1full audit observations/trust-audit/mcp-server/mikkoparkkola__trvl.json · Report an issue / request a re-scan
04

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-0874b0aee82db1BLOCKF55first audit
05

Questions

What is the Trvl MCP server?

Travel MCP server + CLI for AI assistants — flights, hotels, trains, cars, ferries, price alerts. No API keys, single Go binary. 1 smart MCP tool + 66 aliases (98.9% smaller tools/list). Works with Claude, Cursor, Windsurf, Codex.

Is Trvl safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (55/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does Trvl need?

It reads AFKLM_KEY, TRVL_MCP_OAUTH_CLIENT_SECRET, TRVL_MCP_READ_TOKEN, TRVL_MCP_TOKEN and TRVL_MCP_WRITE_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does Trvl run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as trvl-heartbeat.

How current is this page?

The grade is for one exact copy of the source (74b0aee82db1), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement