<?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: Jan Herklotz</title>
    <description>The latest articles on DEV Community by Jan Herklotz (@washedguy).</description>
    <link>https://dev.to/washedguy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4241971%2Fb10ec98c-463f-423c-8e97-419b73ecbab9.webp</url>
      <title>DEV Community: Jan Herklotz</title>
      <link>https://dev.to/washedguy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/washedguy"/>
    <language>en</language>
    <item>
      <title>Building a Telnyx Adapter for Chat SDK</title>
      <dc:creator>Jan Herklotz</dc:creator>
      <pubDate>Fri, 13 Nov 2026 00:54:47 +0000</pubDate>
      <link>https://dev.to/washedguy/building-a-telnyx-adapter-for-chat-sdk-53i1</link>
      <guid>https://dev.to/washedguy/building-a-telnyx-adapter-for-chat-sdk-53i1</guid>
      <description>&lt;p&gt;I built an open-source adapter that connects &lt;a href="https://telnyx.com" rel="noopener noreferrer"&gt;Telnyx&lt;/a&gt; to &lt;a href="https://chat-sdk.dev" rel="noopener noreferrer"&gt;Chat SDK&lt;/a&gt;, so you can build bots that send and receive SMS and MMS messages.&lt;/p&gt;

&lt;p&gt;The adapter supports group MMS, scheduled messages, media attachments, and delivery receipts. It also verifies incoming Telnyx webhooks using Ed25519 signatures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Install the adapter alongside Chat SDK and a state adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm install chat-adapter-telnyx chat @chat-adapter/state-memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure it with your Telnyx API key, phone number, and public key:&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="n"&gt;createMemoryState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"@chat-adapter/state-memory"&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="nc"&gt;Chat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"chat"&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="n"&gt;createTelnyxAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"chat-adapter-telnyx"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;bot&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;Chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"mybot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;adapters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;telnyx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createTelnyxAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TELNYX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TELNYX_PHONE_NUMBER&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TELNYX_PUBLIC_KEY&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="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="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createMemoryState&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="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDirectMessage&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="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&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;await&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`You said: ${message.text}`&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;You’ll also need to route incoming Telnyx webhooks to &lt;code&gt;bot.webhooks.telnyx&lt;/code&gt;. The &lt;a href="https://github.com/washedguy/chat-adapter-telnyx#readme" rel="noopener noreferrer"&gt;README&lt;/a&gt; includes a Next.js example and setup details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;Chat SDK provides a common interface for building chat bots across platforms. I wanted to use that same approach for SMS and MMS through Telnyx.&lt;/p&gt;

&lt;p&gt;The adapter is open source and available on &lt;a href="https://github.com/washedguy/chat-adapter-telnyx" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/chat-adapter-telnyx" rel="noopener noreferrer"&gt;npm&lt;/a&gt;. Feedback, issues, and contributions are welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building MCP Servers for Product Search and Availability</title>
      <dc:creator>Jan Herklotz</dc:creator>
      <pubDate>Fri, 13 Nov 2026 00:54:04 +0000</pubDate>
      <link>https://dev.to/washedguy/building-mcp-servers-for-product-search-and-availability-agm</link>
      <guid>https://dev.to/washedguy/building-mcp-servers-for-product-search-and-availability-agm</guid>
      <description>&lt;p&gt;I recently built a few MCP servers that let AI assistants search listings, find products, and check prices and availability.&lt;/p&gt;

&lt;p&gt;The idea was simple: instead of opening several websites and searching each one manually, I wanted to ask an assistant to find what I was looking for.&lt;/p&gt;

&lt;p&gt;So far, I’ve built servers for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/washedguy/apple-store-mcp" rel="noopener noreferrer"&gt;Apple Store&lt;/a&gt;&lt;/strong&gt;: products, configurations, prices, delivery estimates, and pickup availability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/washedguy/mediamarkt-saturn-mcp" rel="noopener noreferrer"&gt;MediaMarkt, MediaWorld, and Saturn&lt;/a&gt;&lt;/strong&gt;: product search, store search, and pickup availability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/washedguy/maxgaming-mcp" rel="noopener noreferrer"&gt;MaxGaming&lt;/a&gt;&lt;/strong&gt;: gaming products, prices, and availability across storefronts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/washedguy/kleinanzeigen-mcp" rel="noopener noreferrer"&gt;Kleinanzeigen&lt;/a&gt;&lt;/strong&gt;: searching and reading listings&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;MCP gives each server a consistent way to expose tools to an assistant. The more interesting work is figuring out how to get useful data from each site and return it in a form the assistant can work with.&lt;/p&gt;

&lt;p&gt;Every site is different. Product pages expose options and variants differently, availability depends on the storefront or location, and search results don’t always match the query as closely as you’d expect.&lt;/p&gt;

&lt;p&gt;There’s also a difference between “unavailable” and “I couldn’t check.” If a request fails or data is missing, the assistant needs to know rather than treating it as an out-of-stock result.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;I’m interested in making these servers easier to use and improving coverage where product pages or storefronts behave differently.&lt;/p&gt;

&lt;p&gt;They’re all open source, so feel free to try them out, report issues, or contribute. I’d also be interested to hear what other stores or services would be useful to connect through MCP.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
