কম্পিউটার টিউটোরিয়াল

Redis দিয়ে MCP ডেভেলপমেন্ট ত্বরান্বিত করুন: ফাস্ট, কাস্ট-ইফেক্টিভ সমাধান

Model Context Protocol (MCP) দ্রুত AI মডেলগুলাকে এক্সটার্নাল টুল এবং ডেটা সোর্সের সাথে কানেক্ট করার স্ট্যান্ডার্ড উপায় হিসেবে উন্নীত হচ্ছে। MCP অডপশন বাড়ার সাথে সাথে, ডেভেলপাররা খুঁজে পাচ্ছেন যে রোবাস্ট, প্রোডাকশন-রেডি MCP ইমপ্লিমেন্টেশন বানাতে হলে শুধু স্পেস ফলো করার চেয়ে বেশি দরকার: সেটি দরকার সঠিক ইনফ্রাস্ট্রাকচার। এই পোস্টে, আমরা এক্সপ্লোর করব কীভাবে Redis তিনটি আলাদা MCP ইউজ কেসকে পাওয়ার দেয়: Vercel-এর SSE ইমপ্লিমেন্টেশনে ডিস্ট্রিবিউটেড সার্ভারলেস ফাংশন কোঅর্ডিনেট করা, লং-রানিং স্ট্রিমের জন্য ইভেন্ট রিজুমেবিলিটি সক্ষম করা, এবং Clerk-এর সাথে সিকিউর OAuth ফ্লো ম্যানেজ করা।

MCP ট্রান্সপোর্ট বোঝা

আমাদের উদাহরণগুলোতে ডুব দেওয়ার আগে, সংক্ষেপে জানি MCP কীভাবে কমিউনিকেশন হ্যান্ডেল করে। MCP দুটি ট্রান্সপোর্ট সাপোর্ট করে: Stdio লোকাল সার্ভারের জন্য এবং Streamable HTTP রিমোট সার্ভারের জন্য। অতীতে, রিমোট সার্ভারের জন্য SSE (Server-Sent Events) ট্রান্সপোর্টও ছিল, যা এখন ডিপ্রিকেটেড।

SSE থেকে Streamable HTTP-এ ট্রানজিশন MCP রিয়েল-টাইম কমিউনিকেশন হ্যান্ডেল করার প্রক্রিয়ার একটি বিবর্তন রিপ্রেজেন্ট করে, কিন্তু অনেক এক্সিস্টিং ইমপ্লিমেন্টেশন এখনও SSE প্যাটার্নের ওপর নির্ভরশীল। চলুন দেখি কীভাবে Redis সেটা মডেলের একটি মূল চ্যালেঞ্জ সমাধান করেছিল।

ইউজ কেস ১: Redis Pub/Sub দিয়ে SSE

যখন Vercel CTO Malte তাদের MCP হ্যান্ডলার বানাচ্ছিলেন, তিনি একটি ক্লাসিক সার্ভারলেস চ্যালেঞ্জের সম্মুখীন হন: কীভাবে একাধিক এন্ডপয়েন্টের মাঝপথে কোঅর্ডিনেট করবেন যখন প্রতিটি রিকোয়েস্ট একটি আলাদা সার্ভারলেস ফাংশন দ্বারা হ্যান্ডেল করা হতে পারে?

SSE ট্রান্সপোর্ট মডেলে, দুটি ক্রিটিক্যাল এন্ডপয়েন্ট আছে: /sse কানেকশন মেইনটেইন করার জন্য এবং /message ক্লায়েন্ট মেসেজ রিসিভ করার জন্য। এখানে সমস্যাটা: Vercel-এর মত একটি সার্ভারলেস এনভায়রনমেন্টে, এই এন্ডপয়েন্টগুলো সম্পূর্ণরূপে আইসোলেটেড। সেগুলো মেমরি শেয়ার করে না, এবং /message-এ একটি রিকোয়েস্ট একটি সম্পূর্ণ ভিন্ন ফাংশন ইনস্ট্যান্স দ্বারা হ্যান্ডেল করা হতে পারে যা /sse হ্যান্ডল করছে।

সমাধান? Redis Pub/Sub। যেন Malte X-এ ব্যাখ্যা করেছিলেন:

Redis দিয়ে MCP ডেভেলপমেন্ট ত্বরান্বিত করুন: ফাস্ট, কাস্ট-ইফেক্টিভ সমাধান

ইমপ্লিমেন্টেশন Redis চ্যানেল ব্যবহার করে এন্ডপয়েন্টগুলোকে কোঅর্ডিনেট করে। যখন একটি ক্লায়েন্ট /message-এ একটি মেসেজ পাঠায়, সেটি একটি Redis চ্যানেলে পাবলিশ করে যেটি /sse এন্ডপয়েন্ট সাবস্ক্রাইব করা আছে। /sse এন্ডপয়েন্ট রিকোয়েস্ট প্রসেস করে এবং রেসপন্স আরেকটি চ্যানেলে পাবলিশ করে যেটি /message লিসেন করছে।

Redis দিয়ে MCP ডেভেলপমেন্ট ত্বরান্বিত করুন: ফাস্ট, কাস্ট-ইফেক্টিভ সমাধান

এই প্যাটার্ন কার্যকরভাবে Redisকে একটি মেসেজ বাসে রূপান্তরিত করে যা আইসোলেটেড সার্ভারলেস ফাংশনগুলোর গ্যাপ ব্রিজ করে, সেগুলোক একসাথে কাজ করতে দেয় যেন সেগুলো একই প্রসেসের অংশ। যদিও SSE এখন Streamable HTTP-র সুবিধায় ডিপ্রিকেটেড (অর্থাৎ নতুন MCP ইমপ্লিমেন্টেশন মডার্ন ট্রান্সপোর্ট ব্যবহার করা উচিত), এটি এক্সেলেন্ট উদাহরণ রেডিস ব্যবহার করার জন্য আইসোলেটেড সার্ভারলেস ফাংশনগুলোর মাঝপথে কোঅর্ডিনেশনের জন্য।

ইউজ কেস ২: রিজুমেবিলিটির জন্য ইভেন্ট স্টোর

MCP-এর Streamable HTTP ট্রান্সপোর্টের সবচেয়ে পাওয়ারফুল ফিচারগুলোর একটি হলো এর রিজুমেবিলিটি সাপোর্ট। এই ফিচার ক্লায়েন্টকে একটি স্ট্রিম চালিয়ে যাওয়া দেয় যেখানে সেটা ছেড়ে দিয়েছিল যদি ডিসকানেকশন হয়। এটি প্রোডাকশন অ্যাপ্লিকেশনের জন্য ক্রিটিক্যাল যেখানে নেটওয়ার্ক ইন্টারাপশন অবইডেবল।

MCP স্ট্রিম বোঝা

কেন রিজুমেবিলিটি ম্যাটার করে সেটা বুঝতে, আমাদের MCP স্ট্রিম কী নিয়ে সেটা বুঝতে হবে। কিছু অপারেশন, যেন একটি সিম্পল টুল কল, একটি সিঙ্গেল রেসপন্স রিটার্ন করে। কিন্তু টুলগুলো এক্সিকিউশনের সময় একাধিক ইভেন্টও রিটার্ন করতে পারে server.sendLoggingMessage এর মত মেথড ব্যবহার করে। এই মাল্টি-ইভেন্ট স্ট্রিমগুলোই হলো যেখানে রিজুমেবিলিটি ক্রুশিয়াল। যদি একটি ক্লায়েন্ট হাফওয়ে ডিসকানেক্ট হয়, তবে সেটাকে সারিম বা থেকে পিক আপ করতে পারা উচিত বরং নতুন করে শুরু করার বদলে।

Redis দিয়ে EventStore ইমপ্লিমেন্টেশন

MCP SDK একটি EventStore ইন্টারফেস ডিফাইন করে যেটি দুটি মেথড দাবি করে: storeEvent ইভেন্ট যোগ করার জন্য এবং replayEventsAfter একটি স্পেসিফিক ইভেন্ট আইডি থেকে শুরু করে ইভেন্ট রিট্রিভ করার জন্য। SDK-তে একটি ইন-মেমরি ইমপ্লিমেন্টেশন আছে, কিন্তু প্রোডাকশন ইউজের জন্য আপনাকে পা arsen স্টোরেজ দরকার।

এখানে Redis-বেসড EventStore ইমপ্লিমেন্টেশন:

import { Redis } from '@upstash/redis';
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
import { EventStore } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

export class RedisEventStore implements EventStore {
  private redis: Redis;
  constructor(params: ConstructorParameters<typeof Redis>[0]) {
    this.redis = new Redis(params);
  }

  /** 
   * একটি ইভেন্ট Redis Stream-এ স্টোর করে
   * EventStore.storeEvent ইমপ্লিমেন্ট করে
   */
  async storeEvent(streamId: string, message: JSONRPCMessage): Promise<string> {
    const eventId = await this.redis.xadd(`stream:${streamId}`, '*', {
      message: JSON.stringify(message),
    });
    return eventId;
  }

  /** 
   * একটি স্পেসিফিক ইভেন্ট আইডি এর পরে ঘটা ইভেন্টগুলো রিপ্লে করে
   * EventStore.replayEventsAfter ইমপ্লিমেন্ট করে
   */
  async replayEventsAfter(
    lastEventId: string,
    { send }: { send: (eventId: string, message: JSONRPCMessage) => Promise<void> }
  ): Promise<string> {
    if (!lastEventId) {
      return '';
    }
    // lastEventId থেকে স্ট্রিম আইডি এক্সট্র্যাক্ট করুন
    const streamId = lastEventId.split('-')[0];
    // ধরে নেওয়া হচ্ছে স্ট্রিম আইডি কির অংশ
    if (!streamId) {
      return '';
    }
    let nextId = lastEventId;
    while (true) {
      // স্ট্রিম থেকে ইভেন্ট ফেচ করুন next ID-এর পর থেকে (এক্সক্লুসিভ)
      const events = await this.redis.xrange(`stream:${streamId}`, `(${nextId}`, '+', 10);
      // রিটার্নড অবজেক্টকে এন্ট্রির অ্যারেতে কনভার্ট করুন
      const eventEntries = Object.entries(events);
      if (eventEntries.length === 0) {
        break; // রিপ্লে করার জন্য আর ইভেন্ট নেই
      }
      for (const [eventId, fields] of eventEntries) {
        // নিশ্চিত করুন fields.message এক্সিস্ট করে এবং পার্স করুন
        if (fields && typeof fields === 'object' && 'message' in fields && typeof fields.message === 'string') {
          const message = JSON.parse(fields.message) as JSONRPCMessage;
          await send(eventId, message);
          nextId = eventId; // next ID আপডেট করুন করেন্ট ইভেন্ট আইডিতে
        }
      }
    }
    return streamId;
  }
}

এই ইমপ্লিমেন্টেশন Redis Streams ব্যবহার করে, যা এই ইউজ কেসের জন্য পাֆেক্ট।

একটি সীমাবদ্ধতা

একটি গুরুত্বপূর্ণ ক্যাভিয়েট সম্পর্কে অবগত থাকা উচিত: যখন একটি টুল একাধিক ইভেন্ট পাঠায়, streamId সেট হয় _GET_stream-এ, এবং এই কনস্ট্যান্ট বিভিন্ন স্ট্রিম এবং ইউজার জুড়ে একই থাকে। এর মানে যদি দুজন ইউজার একসাথে একই টুল ব্যবহার করে যেটি একাধিক ইভেন্ট পাঠায়, তাদের ইভেন্টগুলো একই স্ট্রিমে মিক্সড হয়ে যেতে পারে।

আমি অফিসিয়াল রিপোজিটরিতে এই बारेে একটি ইস্যু খুলেছি। রেজোলিউশনের ওপর নির্ভর করে, আমাদের ইমপ্লিমেন্টেশন অ্যাডজাস্ট করতে হতে পারে, এবং প্রয়োজনে আমি এই পোস্ট আপডেট করব।

ইউজ কেস ৩: Clerk-এর MCP OAuth ইমপ্লিমেন্টেশন

MCP স্পেসিফিকেশন অথেন্টিকেশন এবং অথরাইজেশনের সাপোর্ট অন্তর্ভুক্ত করে, যাতে MCP সার্ভাররা সিকিউরলি ক্লায়েন্ট অথেন্টিকেট করতে পারে এবং রিসোর্সে অ্যাক্সেস কন্ট্রোল করতে পারে। স্পেসিফিকেশন একাধিক অথেন্টিকেশন স্কিম সাপোর্ট করে, যার মধ্যে OAuth 2.0, যা এক্সিস্টিং আইডেন্টিটি প্রোভাইডারের সাথে ইন্টিগ্রেট করার জন্য এবং টুল এবং ডেটাতে ইউজার-স্কোপড অ্যাক্সেস ইনেবল করার জন্য বিশেষত উপযোগী।

Clerk MCP SDK-এর OAuthClientProvider ইন্টারফেস ইমপ্লিমেন্ট করে একটি কম্প্রিহেনসিভ OAuth ক্লায়েন্ট বানিয়েছে MCP-র জন্য। তাদের ইমপ্লিমেন্টেশন MCP অ্যাপ্লিকেশনে Redis-এর আরেকটি ক্রিটিক্যাল ইউজ কেস প্রদর্শন করে। আপনি যদি তাদের MCP টুলস দিয়ে শুরু করতে চান, তবে তাদের ডেমো রিপো চেক আউট করুন যা একটি চমৎকার স্ট্রাটিং পয়েন্ট প্রদান করে।

OAuth-এর জন্য স্টোরেজ কেন গুরুত্বপূর্ণ

Clerk তাদের mcp-tools রিপোজিটরিতে ব্যাখ্যা করেছেন, পা arsen স্টোরেজ MCP OAuth ইমপ্লিমেন্টেশনের জন্য দুটি মূল কারণে এসেনশিয়াল:

  1. OAuth ফ্লো একাধিক এন্ডপয়েন্টে ফ্যালায় - ইনিশিয়ালাইজেশন, OAuth কলব্যাক, এবং MCP রিকোয়েস্ট كلها আলাদা সার্ভারলেস ফাংশন দ্বারা হ্যান্ডেল করা হতে পারে শেয়ার্ড মেমরি ছাড়া
  2. MCP কানেকশন লং-রানিং - ইন-মেমরি স্টোরেজের ওপর নির্ভর করলে মেমরি রিকোয়্যারমেন্ট ব্লোট হবে অ্যাপ্লিকেশন স্কেল হলে, এবং যেকোনো সার্ভার রিস্টার্ট সকল সেশন ইনভ্যালিডেট করবে

Redis-এ কী স্টোর হয়

Clerk-এর Redis স্টোর তিনটি টাইপের ডেটা ম্যানেজ করে, প্রতিটির OAuth ফ্লোতে একটি স্পেসিফিক উদ্দেশ্য:

PKCE Verifiers (pkce_verifier_<...>) OAuth ফ্লো শুরু করার সময় এগুলো স্টোর হয় এবং ইউজার অ্যাক্সেস দেয়ার পর আবার পড়া হয়। এগুলো PKCE (Proof Key for Code Exchange) ফ্লোর অংশ, যা OAuth-এ পাবলিক ক্লায়েন্টের জন্য অডিশনাল সিকিউরিটি প্রদান করে নিশ্চিত করে যে ফ্লো শুরু করা অ্যাপ্লিকেশনটিই সেটা কমপ্লিট করছে (RFC 7636-এ ডিফাইন করা মত)।

{
  "value": "XoYQ...",
  "created_at": "2025-10-03T06:27:06.928Z",
  "updated_at": "2025-10-03T06:27:06.928Z"
}

সেশন ডেটা (session_<...>) এটি একটি MCP সেশনের সকল কনফিগারেশন এবং স্টেট স্টোর করে। শুরুতে, এতে MCP এন্ডপয়েন্ট, OAuth কনফিগারেশন, এবং ক্লায়েন্ট ক্রেডেনশিয়াল থাকে। ইউজার অ্যাক্সেস দেয়ার পর, এটি আপডেট হয় অ্যাক্সেস এবং রিফ্রেশ টোকেন দিয়ে। অবশেষে, একটি authComplete ফ্ল্যাগ যোগ হয় ফ্লো ফিনিশ হলে।

{
  "value": {
    "mcpEndpoint": "https://localhost:3001/mcp",
    "oauthRedirectUrl": "https://localhost:3000/oauth_callback",
    "oauthScopes": "openid profile email",
    "mcpClientName": "Clerk MCP Demo",
    "mcpClientVersion": "0.0.1",
    "oauthClientUri": "https://example.com",
    "oauthPublicClient": false,
    "clientId": "8Yb2...",
    "clientSecret": "64YG..."
  },
  "created_at": "2025-10-03T06:27:06.882Z",
  "updated_at": "2025-10-03T06:27:06.882Z"
}

State Parameters (state_<...>) এগুলো OAuth state প্যারামিটারকে সেশন আইডির সাথে ম্যাপ করে, যাতে সেশন ডেটা পাওয়া যায় state ID ব্যবহার করে:

{
  "value": "dX61...",
  "created_at": "2025-10-03T06:27:03.585Z",
  "updated_at": "2025-10-03T06:27:03.585Z"
}

এই আর্কিটেকচার OAuth ফ্লোকে ডিস্ট্রিবিউটেড সার্ভারলেস ফাংশন জুড়ে স্মুথলি কাজ করতে দেয় সিকিউরিটি এবং সেশন ইন্টিগ্রিটি মেইনটেইন করে।

MCP-এর জন্য Redis কেন পারফেক্ট

সকল তিনটি উদাহরণে, আমরা কিছু কমন প্যাটার্ন দেখি যা Redisকে MCP ইনফ্রাস্ট্রাকচারের জন্য আইডিয়াল চয়েস করে তোলে:

Low Latency: MCP অপারেশনগুলো প্রায়শই দ্রুত হতে হয়। Redis-এর ইন-মেমরি আর্কিটেকচার রিয়েল-টাইম AI ইন্টারঅ্যাকশনের জন্য প্রয়োজনীয় রেসপন্স টাইম দেয়।

Pub/Sub Capabilities: যেন আমরা Vercel-এর ইমপ্লিমেন্টেশনে দেখেছি, Redis Pub/Sub ডিস্ট্রিবিউটেড কম্পোনেন্টের মাঝপথে এলিগেন্ট কোঅর্ডিনেশন সক্ষম করে ফুল মেসেজ কিউর কমপ্লেক্সিটি ছাড়া।

Rich Data Structures: ইভেন্ট স্ট্রিমের জন্য Streams, সেশন ডেটার জন্য Hashes, এবং স্টেটের জন্য সিম্পল কি-ভ্যালু পেয়ার। Redis প্রতিটি ইউজ কেসের জন্য সঠিক ডেটা স্ট্রাকচার প্রদান করে।

Built-in Expiration: TTL দিয়ে অটোমেটিক ক্লিনআপ। OAuth টোকেন, ইভেন্ট স্ট্রিম, এবং সেশন ডেটা সব অটোমেটিক্যালি এক্সপায়ার হয়ে যেতে পারে ম্যানুয়াল গারবেজ কালেকশন ছাড়া।

Serverless-Friendly: Upstash Redis-এর মত সমাধানের সাথে, আপনি একটি ফুলি ম্যানেজড, সার্ভারলেস Redis পান যেটি ব্যবহার না হলে জিরো স্কেল করে। MCP ইমপ্লিমেন্টেশনের জন্য পাֆেক্ট যেগুলোর ভেরিয়েবল ওয়ার্কলোড হতে পারে।

MCP স্পেস ফিচারের বাইরে: ব্রডার AI ইকোসিস্টেমে Redis

যদিও আমরা MCP স্পেসিফিকেশনে এক্সপ্লিসিটলি ডিফাইন করা ফিচারগুলোর ওপর ফোকাস করেছি, AI পাওয়ার করার সময় Redis-এর ইউটিলিটি আমরা এক্সপ্লোর করা প্যাটার্নগুলো থেকে বহিরাগত বেস্টেন্ড করে। আমাদের недав ব্লগ পোস্টগুলো এই প্যাটার্নগুলোর কয়েকটি শোकेস করে:

  • AI SDK ইন্টিগ্রেশন - Vercel AI SDK উন্নত করার জন্য Redis ব্যবহার
  • চ্যাট হিস্টরি - মেসেজিং হিস্টরি পা arsen করা

আমাদের নিজস্ব উদাহরণগুলোর বাইরে, কমিউনিটি AI অ্যাপ্লিকেশনের জন্য চমৎকার Redis-পাওয়ারড টুলস বানিয়েছে। Midday-এর ai-sdk-tools স্যুইটে একটি টুল রেজাল্ট ক্যাশিং প্যাকেজ আছে যা Redis ব্যবহার করে AI SDK টুল রেজাল্ট ক্যাশ করার জন্য, যেন এই উদাহরণে দেখানো হয়েছে, ড্রামাটিক্যালি পারফরম্যান্স উন্নত করে এবং খরচ কমায়:

Redis দিয়ে MCP ডেভেলপমেন্ট ত্বরান্বিত করুন: ফাস্ট, কাস্ট-ইফেক্টিভ সমাধান

আপনি যেন MCP সার্ভার, AI এজেন্ট, বা ফুল AI অ্যাপ্লিকেশন বানান, Redis সে ইনফ্রাস্ট্রাকচার লেয়ার প্রদান করে যা আপনার সিস্টেমকে প্রোডাকশন-রেডি, স্কেলেবল, এবং পারফরম্যান্ট বানায়।

উপসংহার

Model Context Protocol এখনও যুবন, কিন্তু এটি দ্রুত AI অ্যাপ্লিকেশনের জন্য এসেনশিয়াল ইনফ্রাস্ট্রাকচারে রূপ নিচ্ছে। যেন আমরা এই তিনটি উদাহরণের মাধ্যমে দেখেছি, Redis MCP ইমপ্লিমেন্টেশনকে রোবাস্ট এবং প্রোডাকশন-রেডি বানাতে একটি ক্রুশিয়াল ভূমিকা পালন করে:

  • Speed and Flexibility: এর স্পিড, ফ্লেক্সিবিলিটি, এবং সার্ভারলেস-ফ্রেন্ডলি আর্কিটেকচারের কম্বিনেশন
  • Cost Reduction: ক্যাশিং ক্যাপাবিলিটি যেটি এক্সপেনসিভ API কল এবং কম্পিউটেশন কমিয়ে দেয়

আপনি যদি MCP দিয়ে বানান, চাহে সার্ভার সাইড হোক বা ক্লায়েন্ট সাইড, Redis আপনার টুলকিটে থাকা উচিত MCP-পাওয়ারড AI অ্যাপ্লিকেশনের জন্য পারফেক্ট কম্প্যানিয়ন হিসেবে। Upstash Redis-এ, আপনি আজই সেকেন্ডগুলোর মধ্যে শুরু করতে পারেন একটি গ্লোবালি উপলব্ধ, সার্ভারলেস Redis দিয়ে যেটি জিরো স্কেল করে যখন ব্যবহার না হয়।


  1. অ্যান্ড্রয়েডে ScrollView-এ ListView কোল্যাপ্স না করে রাখা

  2. HTML <var> ট্যাগ

  3. পাইথনে Seaborn-র violinplot দিয়ে প্রতিটি ভায়োলিন বিভক্ত করার পদ্ধতি

  4. জাভাস্ক্রিপ্ট প্রোটোটাইপে মেথড যোগ করা