agentic-travel-recs
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., "@agentic-travel-recsget travel recommendations for member M-1003"
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.
Agentic Travel Recommendations Service
A multi-tenant travel recommendations service that exposes both a REST API and an MCP server, with partner-specific rule enforcement (recommendation caps, category exclusions). Built as an exploration of MCP server design and multi-tenant rule enforcement patterns for AI-agent-facing internal services.
What it does
An AI agent (e.g. a travel concierge embedded in a partner-branded portal) needs two things from this service:
A member's profile — loyalty tier, past bookings, partner affiliation.
Personalized travel recommendations that respect the partner's business rules.
Different partners have different rules. Some cap recommendations at 3 per session; others exclude entire categories like cruises. The service enforces those rules in a single code path so they can't drift between the REST and MCP interfaces.
Quick start
npm install
npm test # 13 tests: rules engine + integration
npm run demo # spawns the MCP server and walks 4 partner scenarios
npm run dev:api # REST API on :3000
npm run dev:mcp # MCP server on stdioThe demo is an actual MCP client that spawns the server as a subprocess and calls its tools the way an AI agent would.
Seeded scenarios
The mocks include four partners exercising every combination of rule shape:
Member | Partner | Loyalty | Partner rules |
M-1001 | Bank A | Gold | No cap, no exclusions |
M-1002 | Credit Union B | Platinum | Excludes cruises |
M-1003 | Membership Org C | Silver | Cap of 3 recommendations |
M-1004 | Airline D | Gold | Cap of 5, excludes cars and cruises |
Project structure
src/
mcp/server.ts # MCP server, stdio transport, two tools
api/server.ts # REST API (Express)
api/routes/recommendations.ts
services/
recommendationsService.ts # orchestrator — shared by REST & MCP
memberDataService.ts # client for the (mocked) member data upstream
partnerConfigService.ts # client for the (mocked) partner config upstream, 60s TTL cache
rules/partnerRulesEngine.ts # single source of truth for partner-rule enforcement
mocks/ # in-memory mocks of the two upstreams
types/index.ts # shared domain types
utils/logger.ts # pino JSON logger
cli/demo.ts # MCP client that spawns the server and walks the scenarios
tests/ # vitest — unit tests for the rules engine + integration
docker/Dockerfile # multi-stage image; default CMD runs the REST APIArchitecture
Four moving parts:
AI agent speaks MCP.
This service exposes two MCP tools (
get_member_profile,get_recommendations) and an equivalent REST API for non-MCP callers and for debugging.Member data service (mocked) — returns member ID, loyalty tier, partner ID, and last five bookings.
Partner configuration service (mocked, read-only) — returns per-partner rules.
Two design properties matter most:
REST and MCP share the same service layer.
recommendationsService.tsis called from bothapi/routes/recommendations.tsandmcp/server.ts. Partner rules run in exactly one code path — it's structurally impossible to ship an MCP path that bypasses them.Rules enforcement is a pure function.
enforcePartnerRules(candidates, partnerConfig, requestedMax?)insrc/rules/partnerRulesEngine.tshas no I/O and no side effects. Roughly 40 lines with a dedicated unit-test file, so partner-rule regressions can be caught in seconds.
Every response includes an appliedRules block reporting which categories were filtered and how many results were capped — so a downstream agent can explain to a user why cruises aren't showing up, and an on-call engineer can diagnose "empty result" cases without reading logs.
Design trade-offs
stdio MCP transport rather than Streamable HTTP.
Stdio has no public network surface — no auth, no rate limiting, no session management to design. The MCP server co-locates as a sidecar with the AI agent that consumes it. Streamable HTTP would be the upgrade path for remotely-hosted use; the tool contracts wouldn't change.
Rule-based candidate scoring, not ML.
The recommender uses a legible scoring function: baseline + historical-type affinity + tier boost − recent-destination penalty. Swapping in an ML model later would leave the rules engine, MCP tools, and REST contracts untouched. A broken model would silently degrade recommendations; a broken rules engine would violate a partner contract. Ship the trustworthy piece first.
60-second partner config cache.
Short enough that a partner rule change propagates within about a minute, long enough to reduce upstream load by roughly 99% on the hot path. A cache-bust endpoint could be added later for partners that need instant propagation.
Handling partner configuration changes
Partner config is read-only from this service's perspective, so a partner changing their cap or adding an exclusion happens entirely upstream. Within the 60-second TTL, the change is picked up on the next call. The rules engine reads it fresh, and the appliedRules block in the response reflects the new state.
The only case that requires a code change here is if a partner adds a new kind of rule (e.g. a time-of-day restriction). That would need a new field in the PartnerConfig type and a new step in enforcePartnerRules. A new instance of an existing rule shape needs no code change — that's what the four seeded partners demonstrate.
Production considerations
Things designed for the person on-call at 2 a.m.:
Every recommendation call logs one INFO line with
{ memberId, partnerId, returned, filteredCount, cappedCount }. One grep answers "did the rules run?"The
appliedRulesblock on every response means the same question can be answered by a curl, without logs.The rules engine has 7 unit tests including a specific "order matters" test that fails if filter and cap are reversed.
Known error types map to stable HTTP status codes and structured MCP
isError: trueresponses.
Things I'd add before running this in production:
Timeouts and one retry with backoff on upstream calls, plus a circuit breaker with a documented fallback behavior.
Per-partner dashboards for error rate and p99 latency; an alert if
filteredCountsuddenly spikes for a partner (usually the signal that someone shipped a bad config).Load testing with realistic traffic mix to validate the cache TTL choice.
Streamable HTTP transport for MCP if remote hosting becomes a requirement.
About the build process
The initial scaffold — types, mocks, service layer skeleton, and the first pass at the MCP server — was AI-assisted. Everything after that (the Partner D onboarding to prove multi-tenant behavior, the integration test for it, the real readiness probe replacing the stub, and a cross-platform fix for a Windows path bug in the MCP entrypoint) was written by me. The Windows bug is the one I'd point out: the AI's original entrypoint check used import.meta.url === \file://${process.argv[1]}`, which silently fails on Windows because the two sides of the comparison use different path formats. Green unit tests didn't catch it because they never spawn the MCP server as a subprocess. I caught it by running the demo end-to-end, and fixed it by normalizing both sides through pathToFileURL`.
License
MIT — see LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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/aryanyeole/agentic-travel-recs'
If you have feedback or need assistance with the MCP directory API, please join our Discord server