আপনি যদি বছরের পর বছর ধরে PHP অ্যাপ্লিকেশনের ভেতরে বিজনেস লজিক রক্ষণাবেক্ষণ করে থাকেন, তবে Model Context Protocol-এর টিউটোরিয়ালগুলো দেখা আপনার কাছে একটি বন্ধ দরজার বাইরে দাঁড়িয়ে থাকার মতো মনে হতে পারে। প্রায় প্রতিটি গাইডই TypeScript বা Python-কে ধরে নিয়ে চলে। তারা অফিসিয়াল SDK, npm install এবং pip প্যাকেজ নিয়ে আলোচনা করে। এর ফলে বিপুল পরিমাণ বিজনেস ডেটা—যেমন কাস্টমার রেকর্ড, অর্ডারের ইতিহাস, ইনভেন্টরি সিস্টেম—PHP কোডবেসে পড়ে থাকে, যা বর্তমান AI টুলিংয়ের কাছে অদৃশ্য মনে হয়।

সুখবর হলো, MCP-এর জন্য ওই SDKগুলোর প্রয়োজন নেই। MCP কোনো লাইব্রেরি নয়। এটি একটি wire protocol। আপনার রানটাইম যদি standard input থেকে এক লাইন টেক্সট পড়তে পারে, JSON পার্স করতে পারে এবং JSON আউটপুট হিসেবে লিখতে পারে, তবে এটি এই প্রোটোকলটি ব্যবহার করতে সক্ষম। LLM আসার অনেক আগে থেকেই PHP ঠিক এই কাজটিই করে আসছে।

MCP আসলে কী

MCP মানে হলো Model Context Protocol। এর মূল ভিত্তি হলো AI অ্যাসিস্ট্যান্টগুলোকে ডেটা, টুলস এবং এক্সটার্নাল API-এর সাথে সংযুক্ত করার একটি ওপেন স্ট্যান্ডার্ড। প্রতিটি অ্যাসিস্ট্যান্ট বা মডেলের জন্য আলাদা আলাদা কাস্টম ইন্টিগ্রেশন তৈরি করার পরিবর্তে, আপনি একটি কমপ্লায়েন্ট ইন্টারফেস তৈরি করবেন। যে কোনো ক্লায়েন্ট যা MCP বোঝে, সেটি PHP, Laravel বা আপনার নির্দিষ্ট ডেটাবেস স্কিমা সম্পর্কে কিছু না জেনেই আপনার সার্ভারের সাথে কথা বলতে পারবে।

এর ভেতরে MCP ব্যবহার করে JSON-RPC 2.0। এর মানে হলো প্রতিটি রিকোয়েস্ট হলো একটি সাধারণ JSON অবজেক্ট যাতে একটি মেথড নেম, প্যারামিটার এবং একটি ID থাকে। সার্ভার একটি অন্য JSON অবজেক্টের মাধ্যমে রেসপন্স দেয়, যাতে একটি রেজাল্ট অথবা একটি এরর থাকে।

একটি সার্ভার তিনটি primitives প্রকাশ করে:

  • Tools: এমন কিছু অ্যাকশন যা মডেল কল করতে পারে। একটি টুল ডেটাবেস কুয়েরি করতে পারে, স্ট্যাটাস আপডেট করতে পারে বা কোনো থার্ড-পার্টি API কল করতে পারে।
  • Resources: স্ট্যাটিক বা সেমি-স্ট্যাটিক ডেটা যা মডেল একটি URI-এর মাধ্যমে রেফারেন্স হিসেবে ব্যবহার করতে পারে। যেমন ফাইল, কনফিগারেশন ডকুমেন্ট বা রেফারেন্স ডেটাসেট।
  • Prompts: পূর্বনির্ধারিত টেমপ্লেট যা ব্যবহারকারীকে সিস্টেমের সাথে ইন্টারঅ্যাক্ট করতে সাহায্য করে।

মনে রাখার মতো একটি গুরুত্বপূর্ণ কন্ট্রোল পার্থক্য রয়েছে। Tools হলো model-controlled। অ্যাসিস্ট্যান্ট কখন একটি টুল কল করবে তা নিজেই সিদ্ধান্ত নেয়। Resources হলো application-controlled। সার্ভার ঠিক করে কোন ডেটা উপলব্ধ থাকবে এবং মডেল কেবল যা অফার করা হয়েছে তা পড়ে। এটি সঠিকভাবে বজায় রাখা আপনার আর্কিটেকচারকে প্রেডিক্টেবল রাখে। আপনি নিশ্চয়ই চাইবেন না যে একটি মডেল এমন কোনো রিসোর্স খুঁজতে থাকুক যা আসলে টুল হওয়া উচিত ছিল, অথবা এর উল্টোটা।

ট্রান্সপোর্ট কীভাবে কাজ করে

MCP দুটি ট্রান্সপোর্ট মেথড সংজ্ঞায়িত করে, এবং আপনার পছন্দ নির্ধারণ করবে আপনি PHP সাইডটি কীভাবে লিখবেন।

stdio হলো সবচেয়ে সহজ পদ্ধতি। MCP ক্লায়েন্ট আপনার PHP স্ক্রিপ্টটিকে একটি সাবপ্রসেস হিসেবে চালু করে। ক্লায়েন্ট আপনার স্ক্রিপ্টের standard input-এ JSON-RPC মেসেজ লেখে এবং আপনার স্ক্রিপ্ট standard output-এ রেসপন্স লেখে। এখানে ম্যানেজ করার জন্য কোনো সকেট নেই, কোনো পোর্ট খোলার প্রয়োজন নেই এবং কোনো অথেন্টিকেশন হেডার পার্স করার ঝামেলা নেই। যদি আপনার টুল এবং ক্লায়েন্ট একই মেশিনে থাকে, তবে এটি শুরু করার জন্য সাধারণত সঠিক জায়গা।

stdio-এর মাধ্যমে চালানোর জন্য আপনার PHP প্রসেসের ওপর দুটি কঠোর নিয়ম আরোপ করা হয়। প্রথমত, আপনার অ্যাপ্লিকেশনকে কখনোই stdout-এ প্রোটোকল বহির্ভূত ডেটা লেখা উচিত নয়। আপনি যদি কোনো ডিবাগ স্টেটমেন্ট echo করেন বা কোনো PHP notice লিক হতে দেন, তবে তা ক্লায়েন্টের পার্সারকে নষ্ট করে দেবে। সমস্ত লগিং এবং ডায়াগনস্টিকস stderr-এ পাঠান। দ্বিতীয়ত, আউটপুট বাফারিং পুরোপুরি বন্ধ করে দিন। PHP সাধারণত stdout বাফার করতে পছন্দ করে, বিশেষ করে CGI বা ওয়েব কনটেক্সটে, তবে CLI স্ক্রিপ্টও ডেটা ধরে রাখতে পারে। প্রতিটি রেসপন্স অবিলম্বে ফ্লাশ (flush) করুন। আপনি যদি স্ট্রিম ব্যবহার করেন, তবে stream_set_write_buffer(STDOUT, 0) সেট করুন অথবা ইমপ্লিসিট বাফারিং বন্ধ করে দিন যাতে আপনি পাঠানোর সাথে সাথেই ক্লায়েন্ট নিউলাইনটি পেয়ে যায়।

Streamable HTTP ভিন্নভাবে কাজ করে। আপনার PHP অ্যাপ্লিকেশনটি একটি পারসিস্টেন্ট HTTP এন্ডপয়েন্ট হিসেবে চলে, যা সাধারণত POST রিকোয়েস্টের মাধ্যমে অ্যাক্সেস করা হয়। এটি তখন কার্যকর যখন সার্ভার অন্য কোনো হোস্টে থাকে, অথবা যখন আপনি এমন একটি লং-রানিং ডেমোন (daemon) চান যা একাধিক ক্লায়েন্ট ব্যবহার করতে পারে। PHP-তে এর মানে হলো প্রথাগত রিকোয়েস্ট-রেসপন্স সাইকেল (যা প্রতিটি কলের পর শেষ হয়ে যায়) এর পরিবর্তে RoadRunner, FrankenPHP, বা অনুরূপ কোনো প্রসেস ম্যানেজারের অধীনে চালানো।

PHP-তে এটি তৈরি করা

শুরু করার জন্য আপনার কোনো ফ্রেমওয়ার্কের প্রয়োজন নেই। PHP-তে একটি মিনিমাল MCP সার্ভার হলো একটি লুপ যা STDIN থেকে ডেটা পড়ে, JSON ডিকোড করে, একটি হ্যান্ডলারের কাছে পাঠায় এবং রেজাল্ট এনকোড করে।

while ($line = fgets(STDIN)) {
    $request = json_decode($line, true);
    // route to tool or resource handler
    // write JSON-RPC response to STDOUT
}

সেই লুপের ভেতরে আসল কাজ হলো এমন ইন্টারফেস তৈরি করা যা একটি মডেলের জন্য অর্থবহ হয়।

কোড থেকে টুল স্কিমা তৈরি করুন। সমস্যা তৈরির অন্যতম দ্রুততম উপায় হলো আপনার টুলের প্যারামিটারের জন্য হাতে লিখে JSON Schema তৈরি করা এবং সেগুলোকে আপনার প্রকৃত ভ্যালিডেশন লজিকের সাথে সামঞ্জস্যহীন হতে দেওয়া। PHP-তে সমৃদ্ধ রিফ্লেকশন (reflection) ক্ষমতা রয়েছে। আপনার মেথড সিগনেচারগুলো পরীক্ষা করুন, আপনার ফর্ম বা কমান্ড অবজেক্ট থেকে বিদ্যমান ভ্যালিডেশন রুলগুলো পড়ুন এবং সেই সীমাবদ্ধতাগুলো (constraints) থেকে স্কিমা তৈরি করুন। যদি আপনার ইন্টারনাল কোডে একটি বৈধ ইমেল ফরম্যাটের প্রয়োজন হয়, তবে আপনার MCP স্কিমাতেও একই কথা থাকা উচিত। যখন ভ্যালিডেশন রুল পরিবর্তিত হয়, স্কিমাটি স্বয়ংক্রিয়ভাবে আপডেট হয়ে যায়। কোনো অমিল (drift) বা নিঃশব্দ ব্যর্থতা (silent failure) থাকবে না।

প্রোটোকল এরর এবং টুল এরর আলাদা রাখুন। JSON-RPC-এর নিজস্ব এরর স্পেস রয়েছে। এটি ভাঙা প্রোটোকলের জন্য ব্যবহার করুন: যেমন ত্রুটিপূর্ণ JSON, অজানা মেথড বা অনুপস্থিত রিকোয়েস্ট আইডি। যখন একটি টুল সঠিকভাবে কাজ করে কিন্তু কোনো ব্যবসায়িক সমস্যার সম্মুখীন হয়, তখন পেলোডের (payload) ভেতরে একটি এরর ফ্ল্যাগসহ একটি সাধারণ ফলাফল প্রদান করুন। যদি কোনো কাস্টমার লুকআপ টুল কোনো মিল থাকা রেকর্ড খুঁজে না পায়, তবে সেটি প্রোটোকল ক্র্যাশ নয়। {"found": false}-এর মতো একটি স্ট্রাকচার্ড রেজাল্ট প্রদান করলে মডেলটি বুঝতে পারে কী ঘটেছে এবং পরবর্তী পদক্ষেপ নিতে পারে। এটি হয়তো আরও বিস্তৃতভাবে অনুসন্ধান করার চেষ্টা করবে, অথবা ব্যবহারকারীর কাছে স্পষ্টীকরণ চাইতে পারে। পরিবর্তে আপনি যদি একটি JSON-RPC এরর থ্রো করেন, তবে মডেলটি প্রায়ই কনটেক্সট হারিয়ে ফেলে।

দীর্ঘমেয়াদী কাজের জন্য পরিকল্পনা করুন। PHP তৈরি করা হয়েছে স্বল্প সময়ের রিকোয়েস্টের জন্য। একটি ওয়েব রিকোয়েস্ট ৩০ সেকেন্ডের মধ্যে টাইম-আউট হতে পারে, এমনকি CLI স্ক্রিপ্টগুলোও মেমরি বা ধৈর্য শেষ করে দিতে পারে। যদি একটি টুল শেষ হতে কয়েক মিনিট সময় নেয়—যেমন হয়তো এটি একটি বড় রিপোর্ট কম্পাইল করে বা সিস্টেমগুলোর মধ্যে ডেটা সিঙ্ক করে—তবে মডেলটিকে অপেক্ষা করাবেন না। অবিলম্বে একটি জব আইডেন্টিফায়ার (job identifier) রিটার্ন করুন। তারপর সেই আইডি দিয়ে স্ট্যাটাস চেক করার জন্য একটি দ্বিতীয় টুল প্রদান করুন। আপনি প্রগ্রেস বা অগ্রগতি Redis, একটি ডাটাবেস টেবিল, এমনকি ভলিউম কম হলে একটি ফ্ল্যাট ফাইলে সংরক্ষণ করতে পারেন। মডেলটি আইডিটি গ্রহণ করে, পরে পুনরায় চেক করে এবং অবশেষে সম্পন্ন হওয়া ফলাফলটি সংগ্রহ করে।

মডেলের কাছে কী (Keys) থাকলে নিরাপত্তা ব্যবস্থা

একটি AI মডেলকে টুলের অ্যাক্সেস দেওয়া একজন মানুষের মতো নয়। একটি মডেল আক্ষরিক অর্থেই খুব দ্রুত কাজ করে এবং এটি বর্ণনার ভুল ব্যাখ্যা করতে পারে। প্রতিটি এক্সপোজড টুলকে প্রিভিলেজ এসকেলেশন (privilege escalation) ঝুঁকি হিসেবে বিবেচনা করুন।

স্কোপ (scope) কঠোরভাবে সীমিত করুন। কখনোই একটি সাধারণ run_sql টুল এক্সপোজ করবেন না। find_customer_by_email বা update_order_status-এর মতো নির্দিষ্ট এবং সংকীর্ণ টুল তৈরি করুন। মডেলটি শুধুমাত্র আপনি যা নাম দিয়েছেন এবং আপনি যে প্যারামিটারগুলো সংজ্ঞায়িত করেছেন, ঠিক তা-ই করতে সক্ষম হওয়া উচিত।

রিড (read) এবং রাইট (write) পাথ আলাদা রাখুন। রিড-অনলি টুলগুলোর ঝুঁকি কম থাকে। যেকোনো ধ্বংসাত্মক (destructive) কাজের জন্য একটি স্পষ্ট কনফার্মেশন মেকানিজম রাখুন, অথবা এটিকে সম্পূর্ণভাবে একটি দ্বিতীয় সার্ভারে সীমাবদ্ধ রাখুন। আপনার ক্লায়েন্ট যদি সমর্থন করে, তবে একটি রাইট টুল কার্যকর করার আগে মানুষের অনুমোদনের ধাপটি বাধ্যতামূলক করুন।

টুলের বর্ণনা এমনভাবে লিখুন যেন সেগুলো অতিরিক্ত নির্দেশাবলী, কারণ সেগুলো আসলে নির্দেশাবলীই। মডেল কখন একটি টুল কল করবে সে বিষয়ে সুনির্দিষ্ট হোন। যদি কোনো টুল প্রাইসিং বা দাম খোঁজে, তবে তা স্পষ্টভাবে বলুন। যদি কাস্টমার আইডি যাচাই করার পরে এটি ব্যবহার করা উচিত হয়, তবে তা স্পষ্টভাবে উল্লেখ করুন। অস্পষ্ট বর্ণনা অস্পষ্ট আচরণের দিকে পরিচালিত করে।

আপনার আউটপুট ফিল্টার করুন। একটি সম্পূর্ণ Eloquent মডেল বা Doctrine এনটিটি সিরিয়ালাইজ করে তা রেজাল্টে ফেলে দেবেন না। মডেলের আসলে যে ফিল্ডগুলোর প্রয়োজন, শুধুমাত্র সেগুলোই রিটার্ন করুন। ইন্টারনাল ফিল্ড—যেমন ক্রয়মূল্য (cost prices), কর্মচারীদের নোট, বা ডাটাবেস আইডি যা ইন্টারনাল থাকা উচিত—সেগুলো ডেটা ট্রান্সফারের মাধ্যমে বাইরে যাওয়ার প্রয়োজন নেই। আপনার রিটার্ন শেপ (return shape) সম্পর্কে সুনির্দিষ্ট হোন।

সবশেষে, সবকিছু লগ (log) করুন। টুলের নাম, পাস করা আর্গুমেন্ট এবং ফলাফল রেকর্ড করুন। যদি একটি মডেল কোনো ব্যয়বহুল কুয়েরির (expensive query) ওপর লুপ করতে শুরু করে বা অপ্রত্যাশিত ক্রমে টুলগুলো পরীক্ষা করতে থাকে, তবে আপনার লগগুলোই হবে এটি দেখার একমাত্র উপায়।

কোথা থেকে শুরু করবেন

আপনার PHP অ্যাপ্লিকেশনকে একটি AI অ্যাসিস্ট্যান্টের সাথে যুক্ত করতে কোনো SDK মেইনটেইনারের অনুমতির প্রয়োজন নেই। আপনার প্রয়োজন JSON-RPC, একটি লুপ এবং stdout-এর ক্ষেত্রে কিছু শৃঙ্খলা।

প্রথম দিনেই আপনার পুরো API-কে MCP টুল হিসেবে পুনরায় তৈরি করার প্রলোভন থেকে দূরে থাকুন। আপনার প্রতিষ্ঠানের কেউ বারবার জানতে চায় এমন তিনটি রিড-অনলি অপারেশন বেছে নিন। হতে পারে সেটি অর্ডারের স্ট্যাটাস চেক করা, কাস্টমার সামারি আনা, অথবা সাম্প্রতিক ইনভয়েসগুলোর তালিকা দেখা। সেগুলোকে টুল হিসেবে র‍্যাপ (wrap) করুন, stdio-এর মাধ্যমে সার্ভিস করুন এবং একজন সহকর্মীকে সেগুলো ব্যবহার করতে দিন। মডেলটি কী ভালো করছে এবং কোথায় হোঁচট খাচ্ছে তা পর্যবেক্ষণ করুন। ত্রিশটি টুলের পরিকল্পনা করার চেয়ে এই তিনটি টুল থেকে আপনি অনেক বেশি শিখতে পারবেন।

MCP একটি সেতু, আপনার অ্যাপ্লিকেশনের বিকল্প নয়। আপনার PHP কোড ইতিমধ্যে আপনার বিজনেস সম্পর্কে জানে। প্রোটোকলটি কেবল মডেলটিকে সেই সীমানা পেরিয়ে এসে প্রশ্ন করার সুযোগ দেয়।