Stateless MCP server কী এবং এতে কী পরিবর্তন এসেছে
MCP রিভিশন 2026-07-28 থেকে সেশন এবং initialize হ্যান্ডশেক সরিয়ে দেওয়া হয়েছে। আপনার রিভার্স প্রক্সি, হেলথ চেক, টাইমআউট এবং অথেন্টিকেশন কনফিগারেশনে কী প্রভাব পড়বে তা জানুন।
stateless MCP server কী
একটি stateless MCP server অনুরোধের মাঝে কোনো client-specific state সংরক্ষণ করে না। প্রতিটি অনুরোধে প্রোটোকল ভার্সন, client-এর সক্ষমতা এবং সার্ভারের উত্তর দেওয়ার জন্য প্রয়োজনীয় ক্রেডেনশিয়াল থাকে, তাই যেকোনো মেশিনের যেকোনো প্রসেস যেকোনো অনুরোধের উত্তর দিতে পারে। MCP (Model Context Protocol, যা এজেন্টরা টুল ব্যবহারের জন্য ব্যবহার করে) 2026-07-28 রিভিশনে এটিকে একটি নিয়ম হিসেবে নির্ধারণ করেছে, যা initialize হ্যান্ডশেক এবং এর অধীনে থাকা HTTP সেশনকে সরিয়ে দিয়েছে।
এটির মূল অপারেশনাল উদ্দেশ্য এটাই। যে সার্ভার প্রতি ক্লায়েন্টের জন্য কোনো তথ্য জমা রাখে না, সেটি কোনো session affinity ছাড়াই সাধারণ load balancer-এর পেছনে চলতে পারে, deploy-এর সময় ক্লায়েন্টদের সংযোগ বিচ্ছিন্ন না করেই রিস্টার্ট করা যায় এবং একটির পরিবর্তে চারটি অভিন্ন প্রসেস হিসেবে চালানো যায়। একটি session-oriented সার্ভার অতিরিক্ত ব্যবস্থা ছাড়া এই কাজগুলোর কোনোটিই করতে পারে না।
Model Context Protocol একটি stateless প্রোটোকল: একটি অনুরোধ প্রসেস করার জন্য প্রয়োজনীয় সমস্ত তথ্য সেই অনুরোধের মধ্যেই থাকে। একটি সার্ভার প্রতিটি অনুরোধ স্বাধীনভাবে প্রসেস করে; পূর্ববর্তী কোনো অনুরোধ থেকে কোনো state অনুমান করা উচিত নয়, এমনকি একই সংযোগ বা স্ট্রিমের ক্ষেত্রেও নয়।
Stateless মানে এই নয় যে আপনার সার্ভার কিছুই সংরক্ষণ করে না। আপনার database, queue এবং cache আগের মতোই থাকবে। এর অর্থ হলো, প্রোটোকল সংযোগের ওপর কোনো state বহন করে না, তাই সার্ভার কোনো সংযোগ, প্রসেস বা খোলা socket-কে "এই ক্লায়েন্ট, কথোপকথনের মাঝপথে আছে" এমন কোনো সংকেত হিসেবে গণ্য করতে পারবে না।
2026-07-28 সংস্করণে যা অপসারণ করা হয়েছে
2026-07-28 হলো 2026 সালের আগস্ট মাস পর্যন্ত স্পেসিফিকেশনের বর্তমান সংস্করণ। 2025-11-25-এর তুলনায় এটি সেশন সাপোর্ট করার জন্য বিদ্যমান পাঁচটি বিষয় অপসারণ করেছে।
initializeরিকোয়েস্ট এবংnotifications/initializedনোটিফিকেশন। এখানে কোনো হ্যান্ডশেক নেই (SEP-2575)।Mcp-Session-Idহেডার এবং HTTPDELETEব্যবহার করে সেশন টার্মিনেশন (SEP-2567)।- স্বতন্ত্র HTTP
GETস্ট্রিম, যার মাধ্যমে সার্ভার নোটিফিকেশন পুশ করত। এর পরিবর্তেsubscriptions/listenআনা হয়েছে, যা একটি সাধারণ POST রিকোয়েস্ট এবং এর রেসপন্স একটি দীর্ঘস্থায়ী স্ট্রিম। - SSE (server-sent events) স্ট্রিম পুনরায় শুরু করার ক্ষমতা।
Last-Event-IDহেডার এবং প্রতি-ইভেন্ট আইডি সরিয়ে ফেলা হয়েছে, তাই স্ট্রিম বিচ্ছিন্ন হলে চলমান রিকোয়েস্টটি হারিয়ে যায় এবং ক্লায়েন্টকে নতুন রিকোয়েস্ট আইডি দিয়ে নতুন করে রিকোয়েস্ট পাঠাতে হয়। ping,logging/setLevelএবংnotifications/roots/list_changed। লগ লেভেল এখন প্রতি-রিকোয়েস্ট ফিল্ড, যা_meta-এর মধ্যেio.modelcontextprotocol/logLevelহিসেবে থাকে।
একটি মেথড যোগ করা হয়েছে এবং প্রতিটি সার্ভারকে অবশ্যই এটি ইমপ্লিমেন্ট করতে হবে। server/discover একটি কলের মাধ্যমে সার্ভারের সমর্থিত প্রোটোকল সংস্করণ, সক্ষমতা এবং পরিচয় প্রদান করে। এটি হ্যান্ডশেকের সবচেয়ে কাছাকাছি যা অবশিষ্ট আছে, এবং ক্লায়েন্টদের জন্য এটি কল করা ঐচ্ছিক।
কেন প্রোডাকশনে সেশন ট্রান্সপোর্ট চালানো কঠিন ছিল
2025-11-25 এবং এর আগের ভার্সনগুলোতে, একটি সার্ভার ইনিশিয়ালাইজেশনের সময় একটি সেশন আইডি তৈরি করতে পারত এবং InitializeResult-এর মাধ্যমে Mcp-Session-Id হেডারে তা ফেরত পাঠাত। এরপর ক্লায়েন্টকে প্রতিটি পরবর্তী রিকোয়েস্টের সাথে সেই হেডারটি পাঠাতে হতো। নেগোশিয়েট করা প্রোটোকল ভার্সন এবং ক্লায়েন্টের সক্ষমতার তথ্য সার্ভারের মেমরিতে সেই আইডির বিপরীতে জমা থাকত। এই প্রতিটি সিদ্ধান্তের একটি অপারেশনাল খরচ ছিল।
- সার্ভার রিস্টার্ট করলে সেশন টেবিল মুছে যেত। স্পেসিফিকেশন অনুযায়ী, কোনো সার্ভার যদি মৃত সেশন আইডি বহনকারী কোনো রিকোয়েস্ট পেত, তবে তাকে
404 Not Foundদিয়ে উত্তর দিতে হতো এবং ক্লায়েন্টকে নতুন করেInitializeRequestদিয়ে শুরু করতে হতো। ফলে প্রতিটি ডিপ্লয়মেন্ট প্রতিটি সংযুক্ত ক্লায়েন্টের জন্য একটি রিকানেক্ট ইভেন্টে পরিণত হতো। - দ্বিতীয় কোনো রেপ্লিকা প্রথম রেপ্লিকার সেশন সম্পর্কে জানত না। স্কেল আউট করার অর্থ ছিল লোড ব্যালেন্সারে স্টিকি রাউটিং ব্যবহার করা, অথবা এমন একটি শেয়ারড সেশন স্টোর রাখা যা প্রতিটি রেপ্লিকা প্রতিটি রিকোয়েস্টের সময় পড়ত।
- সেশন টেবিল এমন একটি মেমরি ছিল যা অলস (idle) ক্লায়েন্টদের সংখ্যার সাথে বাড়ত।
DELETEঐচ্ছিক ছিল, এবং যে ক্লায়েন্টরা এটি না পাঠিয়ে সংযোগ বিচ্ছিন্ন করত, তাদের এন্ট্রিগুলো সার্ভারে থেকে যেত। - লিস্ট রেজাল্ট প্রতিটি সংযোগের ক্ষেত্রে ভিন্ন হতে পারত, তাই সার্ভারের সামনে ক্যাশিং করা অনিরাপদ ছিল।
সেশন সরিয়ে ফেলার মাধ্যমে এই চারটি সমস্যাই একসাথে দূর হয়। কোনো কনফিগারেশনে হাত দেওয়ার আগে এই পরিবর্তনটি বোঝা জরুরি।
প্রতিটি অনুরোধে এখন যা থাকে
MCP endpoint-এ প্রতিটি POST অনুরোধ স্বতন্ত্র। প্রোটোকল ভার্সন এবং ক্লায়েন্ট ক্যাপাবিলিটি অনুরোধের বডিতে _meta-এর অধীনে থাকে এবং নির্বাচিত ফিল্ডগুলো HTTP হেডার-এ মিরর করা হয়, যাতে কোনো ইন্টারমিডিয়ারি JSON পার্স না করেই সেগুলোর ওপর ভিত্তি করে রাউটিং করতে পারে।
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather
Authorization: Bearer <access token>
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {"location": "Seattle, WA"},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {"name": "ExampleClient", "version": "1.0.0"},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}প্রতিটি অনুরোধে io.modelcontextprotocol/protocolVersion এবং io.modelcontextprotocol/clientCapabilities থাকা বাধ্যতামূলক। clientInfo বাধ্যতামূলক নয়, তবে ক্লায়েন্টদের এটি পাঠানো উচিত। কোনো প্রয়োজনীয় ফিল্ড না থাকলে অনুরোধটি ত্রুটিপূর্ণ হিসেবে গণ্য হবে, তাই সার্ভারকে অবশ্যই JSON-RPC এরর -32602 এবং HTTP 400 Bad Request দিয়ে তা প্রত্যাখ্যান করতে হবে।
প্রতিটি অনুরোধে Mcp-Method হেডার থাকা বাধ্যতামূলক। tools/call, resources/read এবং prompts/get-এর ক্ষেত্রে Mcp-Name থাকা আবশ্যক। হেডারের মান অবশ্যই বডির সাথে মিলতে হবে। যদি সার্ভার বডি প্রসেস করে এবং কোনো অমিল পায়, তবে তাকে অবশ্যই 400 Bad Request এবং এরর কোড -32020, HeaderMismatch দিয়ে তা প্রত্যাখ্যান করতে হবে। এই নিয়মটি থাকার কারণ হলো, হেডার দেখে রাউটিং করা লোড ব্যালেন্সার এবং বডি এক্সিকিউট করা সার্ভার—এই দুটি ভিন্ন উৎস থেকে তথ্য আসে। আপনি যদি এই হেডারগুলোর ওপর ভিত্তি করে রাউটিং বা রেট-লিমিটিং করেন, তবে প্রথমে MCP-Protocol-Version চেক করুন: আগের রিভিশনগুলোতে হেডার এবং বডির মধ্যে কোনো ভ্যালিডেশন ছিল না, তাই সেই ভার্সনগুলোতে হেডারের মান নির্ভরযোগ্য নয়।
ভার্সন অমিল এখন আর হ্যান্ডশেক ব্যর্থতার মতো নয়, বরং এটি একটি সাধারণ প্রতি-অনুরোধ (per-request) ত্রুটি। যে সার্ভার অনুরোধ করা ভার্সনটি সাপোর্ট করে না, সেটি 400 Bad Request এরর কোড -32022, UnsupportedProtocolVersion দিয়ে উত্তর দেবে এবং data.supported-এ কী কী সাপোর্ট করে তার তালিকা দেবে। ক্লায়েন্ট সেই তালিকা থেকে একটি বেছে নিয়ে পুনরায় চেষ্টা করবে।
স্টেট যেখানে স্থানান্তরিত হয়েছে: টোকেন, কার্সার এবং সাবস্ক্রিপশন
স্টেট হারিয়ে যায়নি। এটি এমন জায়গায় স্থানান্তরিত হয়েছে যা আপনি দেখতে এবং লগ করতে পারেন।
ক্রেডেনশিয়াল প্রতিটি রিকোয়েস্টের সাথে যুক্ত থাকে। এখানে কোনো সেশন নেই যার সাথে পরিচয় যুক্ত করা যায়, তাই access token প্রতিটি HTTP কলের সাথে যায় এবং প্রতিবার যাচাই করা হয়। বিস্তারিত নিচে authentication সেকশনে দেওয়া হয়েছে।
কার্সারকে অবশ্যই তার নিজস্ব অবস্থান বহন করতে হয়। tools/list, resources/list, prompts/list এবং resources/templates/list-এ পেজিনেশনের জন্য একটি opaque কার্সার স্ট্রিং ব্যবহৃত হয় এবং ক্লায়েন্টদের অবশ্যই এটি পার্স বা পরিবর্তন করা উচিত নয়। সিঙ্গেল-প্রসেস সার্ভারে সেশনের মাধ্যমে মেমরিতে অফসেট রাখা সাধারণ ছিল। যেহেতু কোনো সেশন নেই, তাই যেকোনো রেপ্লিকা যাতে তালিকাটি পুনরায় শুরু করতে পারে সেজন্য কার্সারটি যথেষ্ট তথ্য বহন করবে। তাই কার্সারের ভেতরে অবস্থান এনকোড করে তা সাইন করুন অথবা এমন স্টোরেজে রাখুন যা সব রেপ্লিকা শেয়ার করে। একটি অবৈধ কার্সার হলে -32602 রিটার্ন করা উচিত। এটি সাইন করুন কারণ একটি opaque কার্সার হলো ক্লায়েন্ট-প্রদত্ত ইনপুট যা আপনার কোড ডিকোড করে এবং বিশ্বাস করে।
সাবস্ক্রিপশন একটি রিকোয়েস্টের অংশ, কানেকশনের নয়। যে ক্লায়েন্ট পরিবর্তনের নোটিফিকেশন চায়, সে subscriptions/listen পাঠায় এবং তাতে প্রয়োজনীয় টাইপগুলোর ফিল্টার উল্লেখ করে: toolsListChanged, promptsListChanged, resourcesListChanged এবং resourceSubscriptions। সার্ভার notifications/subscriptions/acknowledged দিয়ে উত্তর দেয় এবং সেই রেসপন্স স্ট্রিমটি খোলা রাখে। যদি স্ট্রিমটি বিচ্ছিন্ন হয়ে যায়, সার্ভার কিছুই ধরে রাখে না এবং ক্লায়েন্ট পুনরায় তা পাওয়ার জন্য subscriptions/listen পাঠায়।
ক্রস-কল অ্যাপ্লিকেশন স্টেট একটি এক্সপ্লিসিট হ্যান্ডেলে পরিণত হয়। যখন সার্ভারের সত্যিই কলের মধ্যবর্তী কোনো তথ্য মনে রাখার প্রয়োজন হয়, তখন স্পেসিফিকেশনের সমাধান হলো সার্ভার-জেনারেটেড একটি আইডেন্টিফায়ার, যা সাধারণ টুল আর্গুমেন্ট হিসেবে ফেরত পাঠানো হয়। এটি টুল স্কিমাতে দেখা যায়, এটি লগ করা সম্ভব এবং এটি কখনোই কানেকশন দ্বারা উহ্য থাকে না। যে সার্ভারের পেছনে প্রকৃত ব্যবহারকারী-ভিত্তিক ডেটা থাকে, যেমন একটি self-hosted MCP email server, তারা সেশনের পরিবর্তে এই প্যাটার্নটি ব্যবহার করে: মেইলবক্স বা ড্রাফট আইডেন্টিফায়ার একটি টুল আর্গুমেন্ট হিসেবে কাজ করে, ফলে যেকোনো রেপ্লিকা পরবর্তী কলটি গ্রহণ করতে পারে।
ডিপ্লয়মেন্ট: reverse proxy, timeout এবং health check
MCP endpoint হলো এমন একটি path যা POST অনুরোধ গ্রহণ করে। অধিকাংশ ট্রাফিকই হলো ছোট অনুরোধ এবং JSON রেসপন্স, যা যেকোনো proxy সহজেই সামলাতে পারে। ব্যতিক্রম হলো streaming response, যেখানে proxy-এর ডিফল্ট সেটিংস আপনার কাজের বিপরীতে যেতে পারে। ল্যাপটপে ডেমো চালানোর পর যখন আপনি একটি VPS-এ MCP server চালান, তখন এই অংশটিই পরিবর্তিত হয়।
location /mcp {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}proxy_buffering off গুরুত্বপূর্ণ কারণ Nginx ডিফল্টভাবে proxied রেসপন্সগুলো বাফার করে, যা SSE ইভেন্টগুলোকে আটকে রাখে যতক্ষণ না বাফার পূর্ণ হয় বা রেসপন্স শেষ হয়। স্পেসিফিকেশন অনুযায়ী সার্ভারকে SSE রেসপন্সে X-Accel-Buffering: no পাঠানো উচিত এবং Nginx সেই হেডারটিকে গুরুত্ব দেয়, তাই একটি সঠিক সার্ভার আপনার proxy-কে নিজেই সঠিক নির্দেশনা দেয়। এই ডিরেক্টিভটি সেট করুন, কারণ এটি আপনার নিয়ন্ত্রণের অংশ।
proxy_read_timeout ডিফল্টভাবে 60 সেকেন্ডে সেট করা থাকে। একটি subscriptions/listen স্ট্রিম যদি এর চেয়ে বেশি সময় ধরে নিষ্ক্রিয় থাকে, তবে Nginx সেটিকে বন্ধ করে দেয়, আপনার সার্ভার নয়। ফলে আপনার লগে সার্ভারকে সুস্থ দেখালেও ক্লায়েন্টের দিকে স্ট্রিমটি বিচ্ছিন্ন হয়ে যায়। এটি শুধুমাত্র MCP location-এর জন্য বাড়ান, পুরো সার্ভারের জন্য নয়। নিষ্ক্রিয় সময়ে keep-alive হিসেবে SSE কমেন্ট লাইন (কোলন দিয়ে শুরু হওয়া লাইন) পাঠানোর জন্য সার্ভারগুলোকে উৎসাহিত করা হয়, যা মধ্যবর্তী কোনো মাধ্যমকে স্ট্রিম বন্ধ করা থেকে বিরত রাখে।
Caddy-এর জন্য কম কনফিগারেশনের প্রয়োজন হয়। এটি নেটওয়ার্ক দক্ষতার জন্য ডিফল্টভাবে আংশিক বাফার করে এবং রেসপন্সে Content-Type: text/event-stream থাকলে সাথে সাথে তা ফ্লাশ করে দেয়, তাই বাড়তি ডিরেক্টিভ ছাড়াই স্ট্রিমিং কাজ করে।
mcp.example.com {
reverse_proxy 127.0.0.1:8080 {
health_uri /healthz
health_interval 10s
}
}লক্ষ্য করুন health check কোথায় নির্দেশ করছে। GET ব্যবহার করে MCP endpoint-এর দিকে active check দেবেন না, কারণ যে সার্ভার শুধুমাত্র এই রিভিশনটি ইমপ্লিমেন্ট করে, সেটি GET এবং DELETE-এর বিপরীতে 405 Method Not Allowed উত্তর দেয়, আর Caddy-এর ডিফল্ট health method হলো GET। এতে proxy একটি সম্পূর্ণ সুস্থ backend-কে ডাউন হিসেবে চিহ্নিত করবে। proxy-এর জন্য /healthz-এর মতো একটি সাধারণ path ব্যবহার করুন এবং POST-এর মাধ্যমে আলাদাভাবে প্রোটোকল চেক করুন।
curl -sS https://mcp.example.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: server/discover' \
-d '{"jsonrpc":"2.0","id":"health-1","method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'একটি supportedVersions তালিকা বহনকারী 200 মানে হলো প্রসেসটি চালু আছে এবং প্রোটোকল অনুযায়ী কথা বলছে। JSON-RPC error -32601 সহ একটি 404 মানে হলো প্রসেসটি চালু আছে কিন্তু server/discover সার্ভ করছে না, যা প্রতিটি 2026-07-28 সার্ভারের জন্য ইমপ্লিমেন্ট করা বাধ্যতামূলক। -32022 সহ একটি 400 মানে হলো আপনার চেকার এমন একটি ভার্সন চেয়েছে যা এই বিল্ড সাপোর্ট করে না, যা ডিপেন্ডেন্সি আপগ্রেডের পর শনাক্ত করা জরুরি। ওপেন সোর্স Nginx-এ কোনো active health check নেই, তাই upstream-এ passive max_fails এবং fail_timeout ব্যবহার করুন এবং আপনার মনিটরিং থেকে প্রোটোকল চেক চালান।
একটি rolling restart-এর ক্ষেত্রে এখন শুধুমাত্র চলমান অনুরোধগুলোই ক্ষতিগ্রস্ত হয়। ড্রেইন করুন, চলমান POST অনুরোধগুলো শেষ হতে দিন, নতুন প্রসেস চালু করুন এবং ক্লায়েন্ট ব্যর্থ হওয়া অনুরোধগুলো পুনরায় পাঠাবে। যে বিষয়টি আপনি এখনো হারাতে পারেন তা হলো যেকোনো খোলা subscriptions/listen স্ট্রিম, কারণ সেই স্ট্রিমটি একটি নির্দিষ্ট প্রসেসের সাথে সরাসরি সংযুক্ত। Statelessness সেশন অ্যাফিনিটি দূর করেছে, কিন্তু বর্তমানে খোলা কোনো স্ট্রিমে কানেকশন অ্যাফিনিটি দূর করেনি এবং কোনো রাউটিং রুল এটি ঠিক করতে পারে না। ক্লায়েন্ট পার্থক্য বুঝতে পারে: একটি স্ট্রিম যা খালি subscriptions/listen রেজাল্ট দিয়ে শেষ হয় তা সঠিকভাবে বন্ধ হয়েছে, আর যা তা ছাড়া শেষ হয় তা বিচ্ছিন্ন হয়েছে, যাকে ক্লায়েন্ট পুনরায় সংযোগ করার কারণ হিসেবে গণ্য করতে পারে।
প্রথমবারের মতো ক্যাশিং সম্ভব হয়। list মেথড থেকে আসা রেজাল্টগুলো এখন ttlMs এবং cacheScope বহন করে, এবং cacheScope: "public" শেয়ার্ড ইন্টারমিডিয়ারিগুলোকে জানায় যে তারা রেসপন্সটি ক্যাশ করতে পারে। এটি কেবল তখনই নিরাপদ যখন list রেজাল্টগুলো প্রতি কানেকশনে পরিবর্তিত হয় না, যা সেশন সরিয়ে ফেলার সরাসরি ফলাফল।
সেশন না থাকলে কেন অথেন্টিকেশন পরিবর্তিত হয়
সেশন থাকলে, একবার initialize-এ অথেন্টিকেট করে পরবর্তী সবকিছুর জন্য সেশন আইডিকে প্রমাণ হিসেবে ব্যবহার করা সহজ ছিল। এভাবে ব্যবহৃত সেশন আইডি হলো এমন একটি বিয়ারার ক্রেডেনশিয়াল যার কোনো অডিয়েন্স, মেয়াদ বা বাতিলের পথ নেই, যা আপনার নিজস্ব সার্ভার তৈরি করে। সেশন সরিয়ে ফেললে সেই শর্টকাটটিও চলে যায় এবং এর পরিবর্তে আরও কঠোর ব্যবস্থা গ্রহণ করতে হয়।
একটি সুরক্ষিত MCP সার্ভার OAuth 2.1 রিসোর্স সার্ভার হিসেবে কাজ করে। ক্লায়েন্ট থেকে আসা প্রতিটি HTTP রিকোয়েস্টে অবশ্যই Authorization: Bearer <access token> থাকতে হবে এবং সার্ভার প্রতিটি রিকোয়েস্টেই টোকেন যাচাই করে। যাচাইকরণ প্রক্রিয়ায় অডিয়েন্স অন্তর্ভুক্ত থাকে: RFC 8707 (Resource Indicators for OAuth 2.0) অনুযায়ী, সার্ভারকে অবশ্যই নিশ্চিত করতে হবে যে টোকেনটি বিশেষভাবে তার জন্যই ইস্যু করা হয়েছে এবং অন্য কোনো কিছুর জন্য তৈরি টোকেন গ্রহণ বা পাস করা যাবে না। ক্লায়েন্টরা সার্ভারের ক্যানোনিকাল URI সহ resource প্যারামিটার পাঠিয়ে সঠিক অডিয়েন্সের অনুরোধ করে।
ডিসকভারি একটি চ্যালেঞ্জের মাধ্যমে সম্পন্ন হয়। যখন কোনো ব্যবহারযোগ্য টোকেন ছাড়া রিকোয়েস্ট আসে, সার্ভার 401 Unauthorized দিয়ে উত্তর দেয়।
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource",
scope="files:read"ক্লায়েন্ট resource_metadata পড়ে, সেই ডকুমেন্টটি (RFC 9728, OAuth 2.0 Protected Resource Metadata, যা MCP সার্ভারগুলোকে অবশ্যই ইমপ্লিমেন্ট করতে হবে) সংগ্রহ করে, অথরাইজেশন সার্ভার খুঁজে বের করে এবং ফ্লোটি সম্পন্ন করে। পর্যাপ্ত পারমিশন নেই এমন একটি বৈধ টোকেন পেলে 403 Forbidden এর সাথে error="insufficient_scope" এবং সেই অপারেশনের জন্য প্রয়োজনীয় স্কোপগুলো প্রদান করা হয়।
এটি যেভাবে পরিচালনা করবেন তার দুটি ফলাফল রয়েছে। টোকেন যাচাইকরণ এখন প্রতি সেশনে একবারের পরিবর্তে প্রতিটি রিকোয়েস্টে ঘটে, তাই প্রতি কলের জন্য ইন্ট্রোস্পেকশন এন্ডপয়েন্টে নেটওয়ার্ক রাউন্ড ট্রিপ আপনার ল্যাটেন্সিতে প্রভাব ফেলবে: এমন টোকেন ব্যবহার করুন যা লোকালি সিগনেচার, অডিয়েন্স এবং মেয়াদের ভিত্তিতে যাচাই করা যায়, অথবা টোকেনের ভিত্তিতে যাচাইকরণের ফলাফল অল্প সময়ের জন্য ক্যাশ করে রাখুন। এবং যেহেতু পরিচয় ধরে রাখার মতো কোনো সেশন নেই, তাই প্রতিটি কলে টোকেন থেকে অথরাইজেশন গণনা করতে হবে। এটি সেশন মডেলের চেয়ে অনেক বেশি স্বচ্ছ এবং এটি এজেন্ট প্রসেস থেকে ক্রেডেনশিয়াল দূরে রাখার বৃহত্তর অনুশীলনের সাথে সামঞ্জস্যপূর্ণ, যা AI এজেন্ট থেকে সিক্রেট দূরে রাখা অংশে আলোচনা করা হয়েছে।
এই রিভিশন সম্পর্কে যা সত্য এবং যা সত্য নয়
উপরের সবকিছু 2026-07-28 রিভিশন বর্ণনা করে। এটি চিরস্থায়ী MCP বর্ণনা করে না এবং এটি গত বছর আপনার ডেপ্লয় করা সার্ভারকেও বর্ণনা করে না।
2025-11-25 এবং তার আগের ক্লায়েন্ট ও সার্ভারগুলো এখনও হ্যান্ডশেক মডেল ব্যবহার করে। স্পেসিফিকেশন এই রিভিশনগুলোকে লিগ্যাসি (legacy) এবং প্রতি-অনুরোধ-মেটাডেটা (per-request-metadata) রিভিশনগুলোকে আধুনিক (modern) হিসেবে অভিহিত করে। যে সার্ভার শুধুমাত্র এই রিভিশন সমর্থন করে, সেটি কোনো পুরনো ক্লায়েন্টের সাথে যুক্ত হলে MCP এন্ডপয়েন্টে 405 Method Not Allowed থেকে GET বা DELETE উত্তর দেওয়া উচিত, কোনো Mcp-Session-Id হেডার তৈরি বা ইকো না করে তা উপেক্ষা করা উচিত এবং Last-Event-ID উপেক্ষা করা উচিত কারণ স্ট্রিমগুলো পুনরায় শুরু করার যোগ্য (resumable) নয়। একটি ডুয়াল-এরা সার্ভার একই এন্ডপয়েন্টে উভয়ই পরিবেশন করতে পারে: একটি আধুনিক _meta বহনকারী অনুরোধ স্টেটলেসভাবে পরিবেশন করা হয় এবং একটি initialize অনুরোধ পুরনো সেশন সেমান্টিকস নির্বাচন করে।
তাই এর কোনো কিছু বিশ্বাস করার আগে রিভিশন স্ট্রিংটি পরীক্ষা করুন। যদি আপনার SDK এখনও initialize পাঠায়, তবে আপনার ডেপ্লয়মেন্টের জন্য সেশনগুলো এখনও কার্যকর এবং উপরের সেশন-সম্পর্কিত সমস্যাগুলো আপনারই সমাধান করতে হবে। ক্লায়েন্ট সাইডের ক্ষেত্রেও একই কথা প্রযোজ্য: আপনার নিজের মেশিনে থাকা একটি এজেন্ট প্রসেস, যেমন running a coding agent on a VPS-এ বর্ণিত সেটআপ, শুধুমাত্র তখনই এই অর্থে স্টেটলেস হবে যদি এটি যে লাইব্রেরি ব্যবহার করে তা একটি আধুনিক রিভিশন সমর্থন করে। আপনার রানটাইম যে সংস্করণটি নেগোশিয়েট করে তা পড়ুন, তারপর স্পেসিফিকেশনের সংশ্লিষ্ট রিভিশনটি পড়ুন এবং এই পৃষ্ঠাটিকে সামগ্রিকভাবে প্রোটোকল হিসেবে না দেখে একটি নির্দিষ্ট রিভিশনের বর্ণনা হিসেবে বিবেচনা করুন।
FAQ
stateless MCP server মানে কি আমি কোনো কিছু সংরক্ষণ করতে পারব না?
না। Stateless শব্দটি প্রোটোকলের ক্ষেত্রে প্রযোজ্য, আপনার অ্যাপ্লিকেশনের ক্ষেত্রে নয়। ডাটাবেস, কিউ (queue) এবং ক্যাশ (cache) আগের মতোই কাজ করবে। যা পরিবর্তিত হয় তা হলো, একাধিক কল জুড়ে থাকা স্টেট (state) অবশ্যই একটি স্পষ্ট আইডেন্টিফায়ার দ্বারা রেফারেন্স করতে হবে, যা ক্লায়েন্ট প্রতিটি অনুরোধের সাথে পাঠাবে, যেমন টুল আর্গুমেন্টে সার্ভার-প্রদত্ত হ্যান্ডেল। আপনি যা করতে পারবেন না তা হলো সংযোগ থেকে কনটেক্সট অনুমান করা: স্পেসিফিকেশন অনুযায়ী, একটি সার্ভার সক্ষমতা, প্রোটোকল সংস্করণ বা ক্লায়েন্ট পরিচয় নির্ধারণের জন্য একই সংযোগের পূর্ববর্তী অনুরোধের ওপর নির্ভর করতে পারবে না, কারণ প্রতিটি অনুরোধে _meta-এর মাধ্যমে সেই তথ্য সরবরাহ করা হয়।
আমার লোড ব্যালেন্সারে কি এখনো sticky sessions প্রয়োজন?
সাধারণ অনুরোধের জন্য প্রয়োজন নেই। 2026-07-28 রিভিশনের অধীনে প্রতিটি POST তার নিজস্ব প্রোটোকল সংস্করণ, সক্ষমতা এবং ক্রেডেনশিয়াল বহন করে, তাই যেকোনো রেপ্লিকা যেকোনো অনুরোধের উত্তর দিতে পারে এবং round-robin পদ্ধতি ব্যবহার করা নিরাপদ। একমাত্র দীর্ঘস্থায়ী বিষয়টি হলো subscriptions/listen রেসপন্স স্ট্রিম, যা একটি একক প্রসেসের সাথে একটি খোলা সংযোগ। প্রসেসটি শেষ হলে এটিও শেষ হয়ে যায় এবং ক্লায়েন্ট পুনরায় সংযোগ স্থাপনের জন্য subscriptions/listen পাঠায়। এটি সেশন অ্যাফিনিটির পরিবর্তে সংযোগের স্থায়িত্ব (connection lifetime), এবং কোনো রাউটিং রুল এটি প্রতিরোধ করতে পারে না।
Mcp-Session-Id এবং HTTP GET স্ট্রিমের কী হয়েছে?
SEP-2567 এবং SEP-2575-এর অধীনে 2026-07-28 রিভিশনে উভয়ই সরিয়ে ফেলা হয়েছে। শুধুমাত্র এই রিভিশনটি ইমপ্লিমেন্ট করা একটি সার্ভারের MCP এন্ডপয়েন্টে 405 Method Not Allowed থেকে GET এবং DELETE-এর উত্তর দেওয়া উচিত এবং কোনো Mcp-Session-Id হেডার ইকো না করে তা উপেক্ষা করা উচিত। সার্ভার-ইনিশিয়েটেড পরিবর্তন বিজ্ঞপ্তিগুলো এখন একটি স্বতন্ত্র GET স্ট্রিমের পরিবর্তে subscriptions/listen অনুরোধের রেসপন্স স্ট্রিমের মাধ্যমে আদান-প্রদান হয়। যে সার্ভারগুলোকে পুরনো ক্লায়েন্টদের সেবা দেওয়া চালিয়ে যেতে হবে, তারা এই রিভিশনের পাশাপাশি আগের রিভিশনের আচরণও ইমপ্লিমেন্ট করবে।
হ্যান্ডশেক ছাড়া একটি MCP সার্ভারের হেলথ চেক কীভাবে করব?
দুই স্তরের পদ্ধতি ব্যবহার করুন। প্রক্সির অ্যাক্টিভ চেকটি আপনার অ্যাপ্লিকেশনের একটি সাধারণ HTTP পাথে পয়েন্ট করুন, কারণ MCP এন্ডপয়েন্টে একটি GET সঠিকভাবে 405 রিটার্ন করে এবং এটি একটি সুস্থ ব্যাকএন্ডকে ডাউন হিসেবে চিহ্নিত করতে পারে। এরপর server/discover POST করে প্রোটোকলটি পরীক্ষা করুন, যা প্রতিটি 2026-07-28 সার্ভারকে অবশ্যই ইমপ্লিমেন্ট করতে হবে এবং নিশ্চিত করুন যে রিপ্লাইটি HTTP 200 এবং আপনার ক্লায়েন্টদের ব্যবহৃত প্রোটোকল সংস্করণ প্রদর্শন করছে। JSON-RPC এরর -32601 সহ একটি 404 মানে হলো প্রসেসটি চলছে কিন্তু সেই মেথডটি সার্ভ করছে না, এবং -32022 সহ একটি 400 মানে হলো আপনার অনুরোধ করা সংস্করণটি সেই বিল্ড দ্বারা সমর্থিত নয়।