ਮੇਰਾ MCP ਸਰਵਰ ਅਚਾਨਕ ਕੰਮ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੰਦਾ ਸੀ। ਕੋਈ ਕ੍ਰੈਸ਼ ਡੰਪ ਨਹੀਂ। ਲੌਗਸ ਵਿੱਚ ਕੋਈ ਸਟੈਕ ਟ੍ਰੇਸ ਨਹੀਂ। ਕਲਾਇੰਟਸ ਬਿਨਾਂ ਕਿਸੇ ਸ਼ਿਕਾਇਤ ਦੇ ਜੁੜੇ ਰਹਿੰਦੇ ਸਨ, ਫਿਰ ਕੁਝ ਘੰਟਿਆਂ ਬਾਅਦ ਸਭ ਕੁਝ ਚੁੱਪ ਹੋ ਜਾਂਦਾ ਸੀ। ਰਿਕੁਐਸਟਾਂ ਗਾਇਬ ਹੋ ਜਾਂਦੀਆਂ ਸਨ ਅਤੇ ਦੂਜੇ ਪਾਸੇ ਵਾਲਾ AI ਏਜੰਟ ਸਿਰਫ਼ ਖਾਲੀ ਹਵਾ ਪ੍ਰਾਪਤ ਕਰਦਾ ਸੀ।

ਇਹ Model Context Protocol (MCP) ਈਕੋਸਿਸਟਮ ਵਿੱਚ ਇੱਕ ਨਿਰਾਸ਼ਾਜਨਕ ਤੌਰ 'ਤੇ ਆਮ ਕਹਾਣੀ ਹੈ। ਪ੍ਰੋਟੋਕੋਲ ਇਹ ਤੈਅ ਕਰਦਾ ਹੈ ਕਿ AI ਏਜੰਟ ਬਾਹਰੀ ਟੂਲਜ਼ ਦੀ ਖੋਜ ਕਿਵੇਂ ਕਰਦੇ ਹਨ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਕਿਵੇਂ ਕਾਲ ਕਰਦੇ ਹਨ, ਪਰ ਸਪੈਸੀਫਿਕੇਸ਼ਨ ਇਹ ਮੰਨ ਕੇ ਚੱਲਦੀ ਹੈ ਕਿ ਤੁਸੀਂ ਗਲਤੀਆਂ (errors) ਨੂੰ ਖੁਦ ਸੰਭਾਲੋਗੇ। ਜ਼ਿਆਦਾਤਰ ਟਿਊਟੋਰਿਅਲ ਅਤੇ ਸ਼ੁਰੂਆਤੀ ਇੰਪਲੀਮੈਂਟੇਸ਼ਨ ਉਸ ਹਿੱਸੇ ਨੂੰ ਛੱਡ ਦਿੰਦੇ ਹਨ। ਉਹ ਸਿਰਫ਼ 'ਹੈਪੀ ਪਾਥ' (happy path) 'ਤੇ ਧਿਆਨ ਕੇਂਦਰਿਤ ਕਰਦੇ ਹਨ: ਇੱਕ ਫੰਕਸ਼ਨ ਨੂੰ ਐਨੋਟੇਟ ਕਰੋ, ਇਸਨੂੰ ਸਰਵਰ ਰਾਹੀਂ ਐਕਸਪੋਜ਼ ਕਰੋ, ਅਤੇ ਇੱਕ ਸਾਫ਼ ਨਤੀਜਾ ਵਾਪਸ ਕਰੋ। ਉਹ ਸ਼ਾਇਦ ਹੀ ਤੁਹਾਨੂੰ ਇਹ ਦਿਖਾਉਂਦੇ ਹਨ ਕਿ ਕੀ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਤੁਹਾਡੀ ਬਾਹਰੀ API ਵਿੱਚ ਕੋਈ ਨੈੱਟਵਰਕ ਸਮੱਸਿਆ ਆਉਂਦੀ ਹੈ, ਜਾਂ ਜਦੋਂ ਮਾਡਲ ਕਿਸੇ ਪੈਰਾਮੀਟਰ ਦੇ ਨਾਮ ਨੂੰ ਗਲਤ ਤਰੀਕੇ ਨਾਲ ਘੜਦਾ (hallucinates) ਹੈ ਅਤੇ ਗਲਤ ਇਨਪੁਟ ਭੇਜਦਾ ਹੈ। ਨਤੀਜਾ ਇੱਕ ਅਜਿਹਾ ਕਮਜ਼ੋਰ ਸਰਵਰ ਹੁੰਦਾ ਹੈ ਜੋ ਸਿਹਤਮੰਦ ਲੱਗਦਾ ਹੈ ਪਰ ਅਸਲ ਵਿੱਚ ਘੰਟਿਆਂ ਤੋਂ ਬੰਦ ਪਿਆ ਹੁੰਦਾ ਹੈ।

ਖਾਲੀ ਜਵਾਬ (Blank Responses) ਕ੍ਰੈਸ਼ਾਂ ਨਾਲੋਂ ਕਿਉਂ ਵਧੇਰੇ ਮਾੜੇ ਹਨ

ਜਦੋਂ MCP ਟੂਲ ਹੈਂਡਲਰ ਵਿੱਚ ਕੋਈ ਅਣਹੰਡਲਡ ਐਕਸਪੈਕਸ਼ਨ (unhandled exception) ਆ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਟ੍ਰਾਂਸਪੋਰਟ ਲੇਅਰ ਅਕਸਰ ਇਸਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰ ਦਿੰਦੀ ਹੈ। ਸਰਵਰ ਪ੍ਰੋਸੈਸ ਚਲਦਾ ਰਹਿੰਦਾ ਹੈ, ਸੌਕੇਟ ਖੁੱਲ੍ਹਾ ਰਹਿੰਦਾ ਹੈ, ਪਰ ਕਲਾਇੰਟ ਨੂੰ ਇੱਕ ਖਾਲੀ ਜਵਾਬ ਮਿਲਦਾ ਹੈ। ਇਹ ਇੱਕ ਵੱਡੇ ਕ੍ਰੈਸ਼ ਨਾਲੋਂ ਵਧੇਰੇ ਖ਼ਤਰਨਾਕ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡੀ ਮਾਨੀਟਰਿੰਗ ਸ਼ਾਇਦ ਇਸਨੂੰ ਨੋਟ ਨਾ ਕਰੇ। ਪ੍ਰੋਸੈਸ ਅਜੇ ਵੀ ਚੱਲ ਰਿਹਾ ਹੈ। ਪੋਰਟ ਅਜੇ ਵੀ ਲਿਸਨਿੰਗ ਕਰ ਰਿਹਾ ਹੈ। ਫਿਰ ਵੀ ਹਰ ਟੂਲ ਕਾਲ ਕੁਝ ਵੀ ਵਾਪਸ ਨਹੀਂ ਕਰਦੀ।

AI ਮਾਡਲ ਚੁੱਪ ਰਹਿਣ ਨੂੰ ਅਸਫਲਤਾ ਵਜੋਂ ਨਹੀਂ ਲੈਂਦਾ। ਇਹ ਚੁੱਪ ਰਹਿਣ ਨੂੰ ਇੱਕ ਸਫਲ ਕਾਲ ਵਜੋਂ ਲੈਂਦਾ ਹੈ ਜਿਸ ਨੇ ਕੋਈ ਡਾਟਾ ਪੈਦਾ ਨਹੀਂ ਕੀਤਾ। ਉਹ ਖਾਲੀ ਜਵਾਬ ਮਾਡਲ ਨੂੰ ਅੰਦਾਜ਼ੇ ਲਗਾਉਣ (improvise) ਲਈ ਸਿਖਾਉਂਦਾ ਹੈ। ਇਹ ਖਾਲੀ ਥਾਂ ਨੂੰ ਭਰਨ ਲਈ ਤੱਥਾਂ ਨੂੰ ਗਲਤ ਤਰੀਕੇ ਨਾਲ ਘੜਨਾ (hallucinating) ਸ਼ੁਰੂ ਕਰ ਦਿੰਦਾ ਹੈ, ਜਾਂ ਇਹ ਉਹੀ ਟੁੱਟੀ ਹੋਈ ਕਾਲ ਨੂੰ ਵਾਰ-ਵਾਰ ਦੁਹਰਾਉਣ ਦੇ ਲੂਪ ਵਿੱਚ ਫਸ ਜਾਂਦਾ ਹੈ। ਨੈੱਟਵਰਕ ਟਾਈਮਆਊਟ ਜਾਂ ਗਲਤ ਟੂਲ ਆਰਗੂਮੈਂਟ ਵਰਗੀਆਂ ਛੋਟੀਆਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਕਦੇ ਵੀ ਇਸ ਤਰ੍ਹਾਂ ਦੇ ਵਿਵਹਾਰ ਦਾ ਕਾਰਨ ਨਹੀਂ ਬਣਨਾ ਚਾਹੀਦਾ।

ਵੈਪਰ ਪੈਟਰਨ (The Wrapper Pattern): ਰੱਖਿਆ ਦੀਆਂ ਤਿੰਨ ਲਾਈਨਾਂ

ਮੈਂ ਹਰ ਟੂਲ ਹੈਂਡਲਰ ਨੂੰ ਇੱਕ ਪਤਲੀ ਐਰਰ-ਰਿਕਵਰੀ ਲੇਅਰ (error-recovery layer) ਵਿੱਚ ਲਪੇਟ ਕੇ ਇਸਨੂੰ ਠੀਕ ਕੀਤਾ। ਵੈਪਰ ਹਰ ਸੰਭਵ ਅਸਫਲਤਾ ਦੀ ਭਵਿੱਖਬਾਣੀ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਨਹੀਂ ਕਰਦਾ। ਇਹ ਉਹਨਾਂ ਨੂੰ ਸ਼੍ਰੇਣੀਆਂ ਵਿੱਚ ਵੰਡਦਾ ਹੈ ਅਤੇ ਉਸ ਅਨੁਸਾਰ ਜਵਾਬ ਦਿੰਦਾ ਹੈ।

ConnectionError ਅਤੇ TimeoutError
ਇਹ ਉਦੋਂ ਪੈਦਾ ਹੁੰਦੇ

ਜਦੋਂ ਵੀ ਤੁਸੀਂ error payload ਵਾਪਸ ਕਰ ਰਹੇ ਹੋ, ਹਮੇਸ਼ਾ isError ਨੂੰ true 'ਤੇ ਸੈੱਟ ਕਰੋ। ਇਹ ਕਲਾਇੰਟ ਨੂੰ ਇੱਕ ਸਪੱਸ਼ਟ ਸੰਕੇਤ ਦਿੰਦਾ ਹੈ ਕਿ tool call ਅਸਫਲ ਰਿਹਾ ਹੈ, ਜਿਸ ਨਾਲ ਮਾਡਲ ਇਹ ਫੈਸਲਾ ਲੈ ਸਕਦਾ ਹੈ ਕਿ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨੀ ਹੈ, ਸਪੱਸ਼ਟਤਾ ਲਈ ਪੁੱਛਣਾ ਹੈ, ਜਾਂ ਪੂਰੀ ਤਰ੍ਹਾਂ ਵੱਖਰੇ tool ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ।

ਜਾਣੋ ਕਿ ਕਿਸ ਨੂੰ Catch ਕਰਨਾ ਹੈ ਅਤੇ ਕਿਸ ਨੂੰ Kill ਕਰਨਾ ਹੈ

ਆਪਣੇ ਪੂਰੇ ਸਰਵਰ ਨੂੰ ਇੱਕ ਅੰਨ੍ਹੇ try-catch ਵਿੱਚ ਨਾ ਲਪੇਟੋ ਜੋ ਸਭ ਕੁਝ ਨਿਗਲ ਲੈਂਦਾ ਹੈ। ਕੁਝ errors ਦਾ ਮਤਲਬ ਹੈ ਕਿ ਸਰਵਰ ਨੂੰ ਤੁਰੰਤ ਰੁਕ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ। ਜੇਕਰ ਸਟਾਰਟਅੱਪ ਵੇਲੇ ਕੋਈ ਲੋੜੀਂਦੀ environment variable ਗੁੰਮ ਹੈ, ਜਾਂ ਤੁਹਾਡੀ configuration ਫਾਈਲ ਖਰਾਬ ਹੈ, ਤਾਂ request-level 'ਤੇ ਕੀਤੀ ਗਈ ਕੋਈ ਵੀ catching ਮਦਦ ਨਹੀਂ ਕਰੇਗੀ। ਅਜਿਹੀਆਂ fatal errors ਲਈ ਇੱਕ ਖਾਸ exception class ਬਣਾਓ ਅਤੇ ਉਹਨਾਂ ਨੂੰ process ਨੂੰ crash ਕਰਨ ਦਿਓ।

ਨਿਯਮ ਸਧਾਰਨ ਹੈ। ਜੇਕਰ error ਅਸਥਾਈ ਹੈ ਜਾਂ ਕਿਸੇ ਇੱਕ request ਤੱਕ ਸੀਮਤ ਹੈ, ਤਾਂ ਇਸਨੂੰ catch ਕਰੋ ਅਤੇ recover ਕਰੋ। ਜੇਕਰ error ਦਾ ਮਤਲਬ ਹੈ ਕਿ ਹਰ ਅਗਲੀ request ਅਸਫਲ ਹੋਣ ਦੀ ਪੂਰੀ ਸੰਭਾਵਨਾ ਹੈ, ਤਾਂ ਸਰਵਰ ਨੂੰ ਖੁੱਲ੍ਹੇਆਮ (loudly) ਡਿੱਗਣ ਦਿਓ। ਸਟਾਰਟਅੱਪ ਵੇਲੇ ਜਲਦੀ ਹੋਣ ਵਾਲੀ ਅਸਫਲਤਾ ਉਸ ਸਰਵਰ ਨਾਲੋਂ ਕਿਤੇ ਬਿਹਤਰ ਹੈ ਜੋ ਕਈ ਦਿਨਾਂ ਤੱਕ ਖਰਾਬ ਅਵਸਥਾ ਵਿੱਚ ਚੱਲਦਾ ਰਹਿੰਦਾ ਹੈ।

ਲੋੜ ਪੈਣ ਤੋਂ ਪਹਿਲਾਂ Observability ਜੋੜੋ

ਇੱਕ ਵਾਰ ਜਦੋਂ ਤੁਹਾਡਾ wrapper ਤਿਆਰ ਹੋ ਜਾਵੇ, ਤਾਂ ਇਸਨੂੰ structured logging ਦੇ ਨਾਲ ਜੋੜ ਦਿਓ। ਹਰ tool call ਅਤੇ ਉਸਦੇ ਨਤੀਜੇ ਨੂੰ JSON format ਵਿੱਚ log ਕਰੋ। ਇਸ ਵਿੱਚ tool ਦਾ ਨਾਮ, raw arguments, latency, ਅਤੇ ਇਹ ਕਿ ਉਹ ਸਫਲ ਰਿਹਾ, ਅਸਫਲ ਰਿਹਾ, ਜਾਂ retry ਕੀਤਾ ਗਿਆ, ਸ਼ਾਮਲ ਕਰੋ।

ਇਹ ਅਨੁਸ਼ਾਸਨ ਜਲਦੀ ਫਲ ਦਿੰਦਾ ਹੈ। ਜਦੋਂ ਤੁਸੀਂ errors ਵਿੱਚ ਵਾਧਾ ਦੇਖਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ tool ਦੇ ਅਧਾਰ 'ਤੇ filter ਕਰ ਸਕਦੇ ਹੋ ਅਤੇ ਕੁਝ ਹੀ ਮਿੰਟਾਂ ਵਿੱਚ patterns ਪਛਾਣ ਸਕਦੇ ਹੋ। ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਕੋਈ ਖਾਸ external API ਹਰ ਰੋਜ਼ ਇੱਕੋ ਸਮੇਂ 'ਤੇ timeouts ਦੇਣ ਲੱਗ ਜਾਵੇ, ਜੋ ਕਿਸੇ ਅਜਿਹੇ scheduled maintenance window ਵੱਲ ਇਸ਼ਾਰਾ ਕਰਦਾ ਹੋਵੇ ਜਿਸ ਬਾਰੇ ਤੁਹਾਨੂੰ ਪਤਾ ਨਹੀਂ