<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mathis Higuinen</title>
    <description>The latest articles on DEV Community by Mathis Higuinen (@mathis_higuinen_6db9b244c).</description>
    <link>https://dev.to/mathis_higuinen_6db9b244c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3952777%2F20fc0059-d3d7-45bd-9098-6dd7587d49a0.png</url>
      <title>DEV Community: Mathis Higuinen</title>
      <link>https://dev.to/mathis_higuinen_6db9b244c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mathis_higuinen_6db9b244c"/>
    <language>en</language>
    <item>
      <title>Building a multilingual API serving 39,585 visa pairs in 15 languages</title>
      <dc:creator>Mathis Higuinen</dc:creator>
      <pubDate>Tue, 26 May 2026 23:34:53 +0000</pubDate>
      <link>https://dev.to/mathis_higuinen_6db9b244c/building-a-multilingual-api-serving-39585-visa-pairs-in-15-languages-1bcm</link>
      <guid>https://dev.to/mathis_higuinen_6db9b244c/building-a-multilingual-api-serving-39585-visa-pairs-in-15-languages-1bcm</guid>
      <description>&lt;p&gt;How we structured a visa requirements database across 15 languages with ISO standardization, caching layers, and translation pipelines.&lt;/p&gt;

&lt;p&gt;Most travel APIs return data in English. That's fine if your users are American or British. It's useless if they're Japanese, Thai, Arabic-speaking, or any of the 5.5 billion people whose first language isn't English.&lt;/p&gt;

&lt;p&gt;When a Vietnamese traveler looks up visa requirements for France, they need the answer in Vietnamese — not just the visa type, but the required documents list, the application process, the embassy information, the travel tips. Translating "Valid passport with 6 months minimum validity" into 15 languages isn't a string replacement. It's a content localization problem at scale.&lt;/p&gt;

&lt;p&gt;The Orizn Visa API serves 39,585 passport-destination pairs in 15 languages: English, French, Spanish, Portuguese, German, Japanese, Korean, Chinese, Russian, Italian, Arabic, Hindi, Thai, Vietnamese, and Filipino. Here's how the system is structured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why these 15 languages
&lt;/h2&gt;

&lt;p&gt;Not random. These 15 cover approximately 75% of the world's internet users by primary language:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;English&lt;/strong&gt; — lingua franca, baseline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chinese&lt;/strong&gt; — 1.1B speakers, China's visa-free program expanding rapidly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spanish&lt;/strong&gt; — 550M speakers, Latin America is a growing travel market&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hindi&lt;/strong&gt; — 600M speakers, Indian passport holders are one of the most visa-restricted populations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arabic&lt;/strong&gt; — 370M speakers, Gulf states have some of the fastest-growing passports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portuguese&lt;/strong&gt; — 260M speakers, Brazil alone has 210M people&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;French&lt;/strong&gt; — 280M speakers, major passport in Africa and Europe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Japanese, Korean&lt;/strong&gt; — high-value travel markets, strong outbound tourism&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Russian&lt;/strong&gt; — 250M speakers, complex visa landscape post-2022&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;German, Italian&lt;/strong&gt; — core EU passports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thai, Vietnamese, Filipino&lt;/strong&gt; — Southeast Asia, where digital nomads concentrate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each language isn't just a translation — it's a market. A Thai translation means Thai travel bloggers can embed our widgets and Thai developers can build apps with localized visa data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data architecture
&lt;/h2&gt;

&lt;p&gt;The core data model is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;visa_pair {
  passport:     ISO 3166-1 alpha-3  (e.g. "FRA")
  destination:  ISO 3166-1 alpha-3  (e.g. "JPN")
  requirement:  enum                (visa_free | visa_required | e_visa |
                                     visa_on_arrival | eta | no_admission)
  visa_free_days: integer | null
  verified:     boolean
  source_url:   string
  last_updated: timestamp
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;199 passports × 199 destinations = 39,601 theoretical pairs. Some pairs are self-referential (you don't need a visa to visit your own country), bringing the actual count to 39,585.&lt;/p&gt;

&lt;p&gt;Each pair has a base record in English. Translations are stored separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;visa_translation {
  passport:     ISO3
  destination:  ISO3
  lang:         enum (15 values)
  description:  text
  documents:    text[]
  process:      text[]
  tips:         text[]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;39,585 pairs × 15 languages = &lt;strong&gt;593,775 translation records&lt;/strong&gt;. That's the real scale of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The translation pipeline
&lt;/h2&gt;

&lt;p&gt;Raw visa data comes from 136 government portals. Most publish in their national language plus English. Some only publish in their national language.&lt;/p&gt;

&lt;p&gt;The pipeline has 5 stages:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Extraction&lt;/strong&gt; — Pull structured visa rules from government sources. This is the hardest part. Every government formats their visa information differently. Some have clean REST APIs. Most have PDF documents or HTML pages with inconsistent formatting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Normalization&lt;/strong&gt; — Map to the 6 standardized requirement types. A government might say "no visa needed for stays under 90 days" — that maps to &lt;code&gt;visa_free&lt;/code&gt; with &lt;code&gt;visa_free_days: 90&lt;/code&gt;. Another might say "electronic authorization required prior to travel" — that's &lt;code&gt;eta&lt;/code&gt;. The mapping isn't always obvious and edge cases are everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. English baseline&lt;/strong&gt; — Generate the English version with all fields: description, documents_required, process, tips, country_info. This is the canonical record that everything else derives from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Translation&lt;/strong&gt; — Generate the 14 other language versions. This isn't word-for-word translation. Document names, process steps, and tips need to be culturally adapted. "Apply at the embassy" in Japanese includes the Japanese name of the embassy and Japanese-language application forms. "Proof of sufficient funds" in Arabic needs to reflect local banking norms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Verification&lt;/strong&gt; — Cross-check against at least 2 independent sources per pair. The &lt;code&gt;verified&lt;/code&gt; flag indicates whether the data has been confirmed. Unverified pairs are still returned but flagged — better to have data with a caveat than no data at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching strategy
&lt;/h2&gt;

&lt;p&gt;With 593K+ records and 15 language variants, caching is critical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request flow:
Client → API Gateway → Cache (Redis) → Database

Cache key pattern: visa:{passport}:{destination}:{lang}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TTL strategy is split by volatility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;24 hours&lt;/strong&gt; for stable pairs — visa types don't change hourly. A &lt;code&gt;visa_free&lt;/code&gt; pair that's been stable for 3 years doesn't need real-time freshness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 hour&lt;/strong&gt; for recently changed pairs — if Thailand just modified its policy, the cache needs to reflect that quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cache&lt;/strong&gt; for the &lt;code&gt;/changes&lt;/code&gt; endpoint — it queries the diff table directly. When someone asks "what changed this week?", they need the latest data, not a cached snapshot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;/check&lt;/code&gt; endpoint (quick check, no documents) is cached aggressively — it returns 5 fields. The &lt;code&gt;/visa&lt;/code&gt; endpoint (full details with documents, process, tips) has shorter TTLs because embassies can update document requirements at any time.&lt;/p&gt;

&lt;h2&gt;
  
  
  ISO standardization decisions
&lt;/h2&gt;

&lt;p&gt;We use ISO 3166-1 alpha-3 exclusively. Not alpha-2 (&lt;code&gt;FR&lt;/code&gt;, &lt;code&gt;JP&lt;/code&gt;), not country names (&lt;code&gt;France&lt;/code&gt;, &lt;code&gt;Japan&lt;/code&gt;), not IATA codes (&lt;code&gt;CDG&lt;/code&gt;, &lt;code&gt;NRT&lt;/code&gt;). Three reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unambiguous&lt;/strong&gt; — alpha-3 has no collisions across all 199 countries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Universal&lt;/strong&gt; — same codes work regardless of language (a Japanese developer sends &lt;code&gt;FRA&lt;/code&gt;, not &lt;code&gt;フランス&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine-readable&lt;/strong&gt; — 3 uppercase ASCII characters, trivially validatable with a regex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API auto-uppercases inputs (&lt;code&gt;fra&lt;/code&gt; → &lt;code&gt;FRA&lt;/code&gt;) and returns clear error messages for invalid codes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;passport&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; value &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;JP&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; is not a valid ISO 3166-1 alpha-3 code. Did you mean &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;JPN&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;?"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters especially for MCP and agent usage where the LLM might send lowercase or alpha-2 codes. A clear error message lets the agent self-correct and retry.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Start with fewer languages.&lt;/strong&gt; Launching with 15 simultaneously was ambitious. Starting with 5 (English, Spanish, French, Chinese, Arabic) and adding based on demand would have been faster and let us focus quality on the highest-impact languages first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invest in government source monitoring earlier.&lt;/strong&gt; The hardest operational challenge isn't translation — it's knowing when a government changes its visa policy. Thailand's 60→30 day rollback happened via a cabinet resolution. That's not an RSS feed. Building automated monitoring for 136 government portals is an ongoing project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build the diff system from day one.&lt;/strong&gt; We added the &lt;code&gt;/changes&lt;/code&gt; endpoint later. If we'd built temporal versioning into the data model from the start (&lt;code&gt;valid_from&lt;/code&gt;, &lt;code&gt;valid_to&lt;/code&gt; on every record), the change detection and audit trail features would have been trivial instead of retrofitted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the API
&lt;/h2&gt;

&lt;p&gt;The multilingual response in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# English (free, no API key)&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://visa.orizn.app/api/v1/visa/check?passport=JPN&amp;amp;destination=FRA"&lt;/span&gt;

&lt;span class="c"&gt;# Japanese (needs free API key)&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: YOUR_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://visa.orizn.app/api/v1/visa?passport=JPN&amp;amp;destination=FRA&amp;amp;lang=ja"&lt;/span&gt;

&lt;span class="c"&gt;# Arabic&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: YOUR_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://visa.orizn.app/api/v1/visa?passport=JPN&amp;amp;destination=FRA&amp;amp;lang=ar"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quick checks are free, no API key needed. Full details in 15 languages with a free key (3,000 req/month) from &lt;a href="https://visa.orizn.app" rel="noopener noreferrer"&gt;visa.orizn.app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;SDKs: &lt;code&gt;npm install orizn&lt;/code&gt; · &lt;code&gt;pip install orizn&lt;/code&gt; · &lt;code&gt;cargo add orizn&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/MattJeff/orizn-visa-api" rel="noopener noreferrer"&gt;github.com/MattJeff/orizn-visa-api&lt;/a&gt;&lt;/p&gt;

</description>
      <category>apigateway</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Building an MCP Server for Visa Requirements in TypeScript</title>
      <dc:creator>Mathis Higuinen</dc:creator>
      <pubDate>Tue, 26 May 2026 15:15:10 +0000</pubDate>
      <link>https://dev.to/mathis_higuinen_6db9b244c/building-an-mcp-server-for-visa-requirements-in-typescript-165a</link>
      <guid>https://dev.to/mathis_higuinen_6db9b244c/building-an-mcp-server-for-visa-requirements-in-typescript-165a</guid>
      <description>&lt;h2&gt;
  
  
  What is MCP, and why should you care?
&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol (MCP) is an open standard created by Anthropic that lets AI agents connect to external tools and data sources through a unified interface. Think of it as USB-C for AI: one protocol, any agent. Instead of building custom integrations for Claude, GPT, Gemini, and every other model, you build one MCP server and every compatible agent can use it.&lt;/p&gt;

&lt;p&gt;MCP defines a simple contract. Your server exposes &lt;strong&gt;tools&lt;/strong&gt; (functions the AI can call) and &lt;strong&gt;resources&lt;/strong&gt; (data the AI can read). The agent discovers what's available, reads the descriptions, and decides when to use them. The transport layer is pluggable -- stdio for local tools, SSE or HTTP for remote ones.&lt;/p&gt;

&lt;p&gt;The protocol is gaining traction fast. Claude Desktop, Cursor, Windsurf, and dozens of other clients already support it. If you have an API that AI agents should be able to use, wrapping it in MCP is one of the highest-leverage things you can do right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why visa requirements are perfect for MCP
&lt;/h2&gt;

&lt;p&gt;Here's a problem every travel-focused AI agent has: visa requirements. Ask an LLM whether a Brazilian passport holder needs a visa for Japan, and you'll get an answer -- but it might be wrong. Models rely on training data that's months or years old, and visa policies change constantly. Thailand just launched a new 60-day visa exemption. Turkey updated its e-visa rules. The model doesn't know.&lt;/p&gt;

&lt;p&gt;Visa data is structured, query-driven, and time-sensitive. It's exactly the kind of information that should come from a live API, not from parametric memory. An MCP server bridges that gap: the agent recognizes a visa question, calls the tool, and gets current data from a real database.&lt;/p&gt;

&lt;p&gt;That's what we built with the &lt;strong&gt;Orizn Visa MCP Server&lt;/strong&gt; -- a TypeScript MCP server backed by an API covering 39,585 passport-destination pairs in 15 languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture overview
&lt;/h2&gt;

&lt;p&gt;The stack is deliberately minimal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtime&lt;/strong&gt;: Node.js 18+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language&lt;/strong&gt;: TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP SDK&lt;/strong&gt;: &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; (v1.12+)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transport&lt;/strong&gt;: stdio (runs locally alongside the AI client)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Orizn Visa API at &lt;code&gt;https://visa.orizn.app/api/v1/visa&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The server exposes &lt;strong&gt;5 tools&lt;/strong&gt; and &lt;strong&gt;2 resources&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;check_visa_requirement&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full visa details for a passport-destination pair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quick_visa_check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fast yes/no check (free, no API key)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_all_destinations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All destinations for one passport at once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_visa_changes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recent visa policy updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_coverage_stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Database coverage statistics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resources&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;visa://supported-languages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The 15 supported language codes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;visa://country-codes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All 199 ISO3 country codes the API accepts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Code walkthrough
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Server initialization
&lt;/h3&gt;

&lt;p&gt;MCP servers start with a &lt;code&gt;Server&lt;/code&gt; instance and a transport. We use &lt;code&gt;StdioServerTransport&lt;/code&gt;, which communicates over stdin/stdout -- the standard for local MCP servers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orizn-visa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StdioServerTransport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You register capabilities upfront -- &lt;code&gt;tools&lt;/code&gt; and &lt;code&gt;resources&lt;/code&gt; -- so the client knows what to expect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining tools
&lt;/h3&gt;

&lt;p&gt;Tools are defined with a name, description, and JSON Schema for inputs. Here's the core visa check tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;check_visa_requirement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Check visa requirements between any two countries. Returns visa type &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(visa-free, e-visa, visa required, etc.), allowed stay duration, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required documents, step-by-step application process, and travel tips. &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Covers 39,585 passport-destination pairs in 15 languages. &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use this tool when the user asks about visa rules, entry requirements, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;or whether they need a visa to visit a country.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ISO 3166-1 alpha-3 code of the passport (e.g. 'FRA').&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ISO 3166-1 alpha-3 code of the destination (e.g. 'JPN').&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Language code for the response. Defaults to 'en'.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;passport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;destination&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool handler validates inputs and calls the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CallToolRequestSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;check_visa_requirement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateISO3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;passport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateISO3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;destination&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other tools&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;p&gt;Resources let the agent look up reference data without burning an API call. We expose two static resources -- supported languages and valid country codes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ReadResourceRequestSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;visa://supported-languages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
          &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;mimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SUPPORTED_LANGUAGES_RESOURCE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;visa://country-codes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
          &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;mimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;COUNTRY_CODES_RESOURCE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, when the agent isn't sure of a country code, it can check the resource first instead of guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  API client with retry logic
&lt;/h3&gt;

&lt;p&gt;The API client handles timeouts, retries on 5xx errors, and fails fast on 4xx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiresKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;lastError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;MAX_RETRIES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;REQUEST_TIMEOUT_MS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Don't retry client errors -- the request itself is wrong&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InvalidRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;`API returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// 5xx: retry&lt;/span&gt;
      &lt;span class="nx"&gt;lastError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;McpError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;lastError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InternalError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`API request failed after &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;MAX_RETRIES&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; attempts: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastError&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distinction between 4xx and 5xx is important. A 400 means the agent sent bad parameters -- retrying won't help. A 503 means the server hiccupped -- retrying might.&lt;/p&gt;

&lt;h3&gt;
  
  
  ISO3 validation
&lt;/h3&gt;

&lt;p&gt;Country codes are validated against a hardcoded set of 199 codes before hitting the API. This catches the most common error pattern (the LLM sends "JP" instead of "JPN") at the MCP layer with a clear error message, rather than letting it propagate as a cryptic API error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateISO3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paramName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;upper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ISO3_COUNTRY_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InvalidParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;paramName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" value "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" is not a valid ISO 3166-1 alpha-3 country code.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key decisions and lessons learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tool descriptions are your most important code.&lt;/strong&gt; The LLM reads them to decide &lt;em&gt;when&lt;/em&gt; to invoke your tool. Vague descriptions mean the agent won't call your tool when it should. We explicitly state what each tool returns, what it covers (39,585 pairs, 15 languages), and when to use it versus alternatives. This isn't documentation -- it's prompt engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;stdout is sacred.&lt;/strong&gt; In stdio transport, stdout carries MCP protocol messages. If you &lt;code&gt;console.log()&lt;/code&gt; anything, you'll corrupt the protocol stream and crash the connection. All our logging goes to stderr via &lt;code&gt;process.stderr.write()&lt;/code&gt;. This is the #1 mistake people make when building their first MCP server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free tier drives adoption.&lt;/strong&gt; The &lt;code&gt;quick_visa_check&lt;/code&gt; and &lt;code&gt;get_coverage_stats&lt;/code&gt; tools work without an API key. This means anyone can &lt;code&gt;npx orizn-visa-mcp&lt;/code&gt; and immediately test it. Zero friction. If they need full details, they add a key. But the first experience is instant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validate before you fetch.&lt;/strong&gt; Catching "FR" vs "FRA" at the validation layer gives the agent a clear, actionable error ("not a valid ISO 3166-1 alpha-3 code") instead of a generic API 400. The agent can self-correct and retry with the right format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing and distribution
&lt;/h2&gt;

&lt;p&gt;Building the server is half the work. Getting it in front of developers is the other half.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;npm publish&lt;/strong&gt; -- This enables &lt;code&gt;npx orizn-visa-mcp&lt;/code&gt;, the fastest path from discovery to running server. Set the &lt;code&gt;bin&lt;/code&gt; field in &lt;code&gt;package.json&lt;/code&gt; and add the shebang (&lt;code&gt;#!/usr/bin/env node&lt;/code&gt;) to your entry point.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MCP registries&lt;/strong&gt; -- Submit to &lt;a href="https://smithery.ai" rel="noopener noreferrer"&gt;Smithery&lt;/a&gt;, &lt;a href="https://mcp.so" rel="noopener noreferrer"&gt;mcp.so&lt;/a&gt;, and &lt;a href="https://glama.ai/mcp/servers" rel="noopener noreferrer"&gt;Glama&lt;/a&gt;. These are where developers browse for MCP servers. A &lt;code&gt;smithery.yaml&lt;/code&gt; config file handles Smithery's hosted deployment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;README as marketing&lt;/strong&gt; -- Your README is your landing page. Include a clear one-liner, a feature table, installation instructions for every major client (Claude Desktop, Cursor, VS Code), and example outputs. Most developers decide whether to try your server in 30 seconds of scanning the README.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The server is open source and ready to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/MattJeff/orizn-mcp-server" rel="noopener noreferrer"&gt;github.com/MattJeff/orizn-mcp-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/orizn-visa-mcp" rel="noopener noreferrer"&gt;npmjs.com/package/orizn-visa-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run it&lt;/strong&gt;: &lt;code&gt;npx orizn-visa-mcp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API docs&lt;/strong&gt;: &lt;a href="https://visa.orizn.app" rel="noopener noreferrer"&gt;visa.orizn.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building an AI agent that touches travel, immigration, or international logistics, plug this in and your agent gets reliable visa data instead of hallucinated guesses. And if you're building your own MCP server -- steal the patterns. The protocol is simple, the SDK is solid, and the ecosystem is growing fast.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>tutorial</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
