[{"data":1,"prerenderedAt":674},["ShallowReactive",2],{"i-mdi:open-in-new":3,"i-mdi:github":8,"i-mdi:menu":10,"i-local:logo":12,"blog-tool-result-caching":15},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"M14 3v2h3.59l-9.83 9.83l1.41 1.41L19 6.41V10h2V3m-2 16H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7h-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33s1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"currentColor\" d=\"M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z\"\u002F>",{"left":4,"top":4,"width":13,"height":13,"rotate":4,"vFlip":6,"hFlip":6,"body":14},1200,"\u003Cdefs\n     id=\"defs1\" \u002F>\n  \u003Cpath\n     style=\"fill:#326ce5;fill-opacity:1;stroke:#326ce5;stroke-width:54.2178;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:65.7793;stroke-opacity:1;paint-order:stroke fill markers\"\n     id=\"path10\"\n     d=\"M 778.34299,825.61572 273.93527,960.77136 -95.316804,591.51929 39.838835,87.111573 544.24655,-48.044069 913.49863,321.20801 Z\"\n     transform=\"matrix(0.89078213,-0.23868436,0.23868436,0.89078213,126.66226,291.12302)\" \u002F>\n  \u003Cpath\n     style=\"fill:#ffa400;fill-opacity:1;stroke:#ffffff;stroke-width:171.118;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:65.7793;stroke-opacity:1;paint-order:stroke fill markers\"\n     id=\"path10-0-4\"\n     d=\"M 778.34299,825.61572 273.93527,960.77136 -95.316804,591.51929 39.838835,87.111573 544.24655,-48.044069 913.49863,321.20801 Z\"\n     transform=\"matrix(0.56447964,-0.15125188,0.15125188,0.56447964,300.05065,404.26778)\" \u002F>\n  \u003Cg\n     id=\"g24\"\n     transform=\"translate(-0.00289,-1.818185)\">\n    \u003Cpath\n       style=\"fill:#ffa400;fill-opacity:1;stroke:#ffffff;stroke-width:25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:65.7793;stroke-opacity:1;paint-order:stroke fill markers\"\n       d=\"M 236.36364,809.09091 960.89972,390.77981\"\n       id=\"path22\" \u002F>\n    \u003Cpath\n       style=\"fill:#ffa400;fill-opacity:1;stroke:#ffffff;stroke-width:25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:65.7793;stroke-opacity:1;paint-order:stroke fill markers\"\n       d=\"m 236.36364,389.09091 727.2785,419.89444\"\n       id=\"path23\" \u002F>\n    \u003Cpath\n       style=\"fill:#ffa400;fill-opacity:1;stroke:#ffffff;stroke-width:25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:65.7793;stroke-opacity:1;paint-order:stroke fill markers\"\n       d=\"M 600.18182,1010.9091 V 192.72727\"\n       id=\"path24\" \u002F>\n  \u003C\u002Fg>\n  \u003Ccircle\n     style=\"fill:none;stroke:#ffffff;stroke-width:42.7667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:65.7793;paint-order:stroke fill markers\"\n     id=\"path1\"\n     cx=\"261.54996\"\n     cy=\"402.17349\"\n     r=\"19.439373\" \u002F>\n  \u003Ccircle\n     style=\"fill:none;stroke:#ffffff;stroke-width:42.7667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:65.7793;paint-order:stroke fill markers\"\n     id=\"path1-3\"\n     cx=\"257.91364\"\n     cy=\"793.18634\"\n     r=\"19.439373\" \u002F>\n  \u003Ccircle\n     style=\"fill:none;stroke:#ffffff;stroke-width:42.7667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:65.7793;paint-order:stroke fill markers\"\n     id=\"path1-5\"\n     cx=\"599.82275\"\n     cy=\"993.0954\"\n     r=\"19.439373\" \u002F>\n  \u003Ccircle\n     style=\"fill:none;stroke:#ffffff;stroke-width:42.7667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:65.7793;paint-order:stroke fill markers\"\n     id=\"path1-2\"\n     cx=\"939.64093\"\n     cy=\"794.36816\"\n     r=\"19.439373\" \u002F>\n  \u003Ccircle\n     style=\"fill:none;stroke:#ffffff;stroke-width:42.7667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:65.7793;paint-order:stroke fill markers\"\n     id=\"path1-8\"\n     cx=\"599.55005\"\n     cy=\"207.73181\"\n     r=\"19.439373\" \u002F>\n  \u003Ccircle\n     style=\"fill:none;stroke:#ffffff;stroke-width:42.7667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:65.7793;paint-order:stroke fill markers\"\n     id=\"path1-1\"\n     cx=\"939.91364\"\n     cy=\"403.18637\"\n     r=\"19.439373\" \u002F>\n  \u003Ccircle\n     style=\"fill:none;stroke:#ffffff;stroke-width:42.7667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:65.7793;paint-order:stroke fill markers\"\n     id=\"path1-1-7\"\n     cx=\"600\"\n     cy=\"600\"\n     r=\"19.439373\" \u002F>",{"id":16,"title":17,"author":18,"authorUrl":19,"body":20,"category":659,"date":660,"description":661,"extension":662,"image":659,"meta":663,"navigation":664,"path":665,"seo":666,"series":659,"stem":667,"tags":668,"__hash__":673},"blog\u002Fblog\u002Ftool-result-caching.md","Your agent just called the same tool 20 times","rdmnl","https:\u002F\u002Fgithub.com\u002Frdmnl",{"type":21,"value":22,"toc":649},"minimark",[23,27,31,43,48,56,59,62,66,178,185,191,195,198,269,276,346,349,353,368,371,378,382,385,421,425,428,479,482,485,619,622,626,629,632,636,639,645],[24,25,17],"h1",{"id":26},"your-agent-just-called-the-same-tool-20-times",[28,29,30],"p",{},"Watch an agent work through a complex task and you'll see it. The same database lookup, three times in a row. The same search query, once per reasoning iteration. The same API call, identical arguments, identical results - billed fresh every single time.",[28,32,33,34,38,39,42],{},"This isn't a bug. It's how reasoning loops work. The model doesn't remember that it already called ",[35,36,37],"code",{},"get_project"," with ",[35,40,41],{},"{\"key\": \"alpha\"}"," two turns ago. So it calls it again. And again. And your external API meter keeps ticking.",[44,45,47],"h2",{"id":46},"the-math-is-brutal","The math is brutal",[28,49,50,51,55],{},"A reasoning agent working through a multi-step problem makes 20-50 tool calls per task. In our benchmarks, ",[52,53,54],"strong",{},"80% of those calls are duplicates"," - same tool, same arguments, same result. That's 16 out of 20 calls that accomplish nothing except burning latency and API quota.",[28,57,58],{},"Each call hits your MCP server, which hits your database or external API, which takes 50-200ms of wall time. Multiply by the number of agents, the number of tasks per hour, and you're looking at thousands of wasted calls per day.",[28,60,61],{},"The worst part: the model gets identical text back every time. It doesn't know or care whether the result came from a fresh API call or from memory.",[44,63,65],{"id":64},"the-fix-three-lines-of-yaml","The fix: three lines of YAML",[67,68,73],"pre",{"className":69,"code":70,"language":71,"meta":72,"style":72},"language-yaml shiki shiki-themes github-dark","# researcher-agent.yaml\ntools:\n  mcp:\n    - name: search\n      url: http:\u002F\u002Fsearch-mcp.tools.svc:8080\n      cache:\n        enabled: true\n        ttlSeconds: 600\n        excludeTools:\n          - create_bookmark\n","yaml","",[35,74,75,84,95,103,119,130,138,150,161,169],{"__ignoreMap":72},[76,77,80],"span",{"class":78,"line":79},"line",1,[76,81,83],{"class":82},"sAwPA","# researcher-agent.yaml\n",[76,85,87,91],{"class":78,"line":86},2,[76,88,90],{"class":89},"s4JwU","tools",[76,92,94],{"class":93},"s95oV",":\n",[76,96,98,101],{"class":78,"line":97},3,[76,99,100],{"class":89},"  mcp",[76,102,94],{"class":93},[76,104,106,109,112,115],{"class":78,"line":105},4,[76,107,108],{"class":93},"    - ",[76,110,111],{"class":89},"name",[76,113,114],{"class":93},": ",[76,116,118],{"class":117},"sU2Wk","search\n",[76,120,122,125,127],{"class":78,"line":121},5,[76,123,124],{"class":89},"      url",[76,126,114],{"class":93},[76,128,129],{"class":117},"http:\u002F\u002Fsearch-mcp.tools.svc:8080\n",[76,131,133,136],{"class":78,"line":132},6,[76,134,135],{"class":89},"      cache",[76,137,94],{"class":93},[76,139,141,144,146],{"class":78,"line":140},7,[76,142,143],{"class":89},"        enabled",[76,145,114],{"class":93},[76,147,149],{"class":148},"sDLfK","true\n",[76,151,153,156,158],{"class":78,"line":152},8,[76,154,155],{"class":89},"        ttlSeconds",[76,157,114],{"class":93},[76,159,160],{"class":148},"600\n",[76,162,164,167],{"class":78,"line":163},9,[76,165,166],{"class":89},"        excludeTools",[76,168,94],{"class":93},[76,170,172,175],{"class":78,"line":171},10,[76,173,174],{"class":93},"          - ",[76,176,177],{"class":117},"create_bookmark\n",[28,179,180,181,184],{},"That's it. Every tool on the ",[35,182,183],{},"search"," MCP server now caches results for 10 minutes. Same arguments, same tool name = cache hit. The agent gets the exact same response in nanoseconds instead of milliseconds. The MCP server never sees the duplicate call.",[28,186,187,190],{},[35,188,189],{},"excludeTools"," is the safety valve. Tools that create, update, or delete - anything non-idempotent - go on this list and always hit the real server.",[44,192,194],{"id":193},"what-actually-happens","What actually happens",[28,196,197],{},"Here's a real benchmark. 20 tool calls, 4 unique argument combinations, 50ms simulated MCP latency:",[199,200,201,217],"table",{},[202,203,204],"thead",{},[205,206,207,211,214],"tr",{},[208,209,210],"th",{},"Metric",[208,212,213],{},"Without cache",[208,215,216],{},"With cache",[218,219,220,232,243,254],"tbody",{},[205,221,222,226,229],{},[223,224,225],"td",{},"MCP server hits",[223,227,228],{},"20",[223,230,231],{},"4",[205,233,234,237,240],{},[223,235,236],{},"Total latency",[223,238,239],{},"1,029ms",[223,241,242],{},"205ms",[205,244,245,248,251],{},[223,246,247],{},"Avg per call",[223,249,250],{},"51ms",[223,252,253],{},"10ms",[205,255,256,261,264],{},[223,257,258],{},[52,259,260],{},"Savings",[223,262,263],{},"-",[223,265,266],{},[52,267,268],{},"80% fewer calls, 80% faster",[28,270,271,272,275],{},"On a cache hit, the response returns in ",[52,273,274],{},"42 nanoseconds",". Not milliseconds. Nanoseconds. The model sees identical output:",[67,277,281],{"className":278,"code":279,"language":280,"meta":72,"style":72},"language-json shiki shiki-themes github-dark","{\n  \"key\": \"project-alpha\",\n  \"value\": { \"budget\": 50000, \"status\": \"active\" },\n  \"created_at\": \"2026-04-27T10:27:55Z\"\n}\n","json",[35,282,283,288,301,331,341],{"__ignoreMap":72},[76,284,285],{"class":78,"line":79},[76,286,287],{"class":93},"{\n",[76,289,290,293,295,298],{"class":78,"line":86},[76,291,292],{"class":148},"  \"key\"",[76,294,114],{"class":93},[76,296,297],{"class":117},"\"project-alpha\"",[76,299,300],{"class":93},",\n",[76,302,303,306,309,312,314,317,320,323,325,328],{"class":78,"line":97},[76,304,305],{"class":148},"  \"value\"",[76,307,308],{"class":93},": { ",[76,310,311],{"class":148},"\"budget\"",[76,313,114],{"class":93},[76,315,316],{"class":148},"50000",[76,318,319],{"class":93},", ",[76,321,322],{"class":148},"\"status\"",[76,324,114],{"class":93},[76,326,327],{"class":117},"\"active\"",[76,329,330],{"class":93}," },\n",[76,332,333,336,338],{"class":78,"line":105},[76,334,335],{"class":148},"  \"created_at\"",[76,337,114],{"class":93},[76,339,340],{"class":117},"\"2026-04-27T10:27:55Z\"\n",[76,342,343],{"class":78,"line":121},[76,344,345],{"class":93},"}\n",[28,347,348],{},"Same string, whether it came from the MCP server or from memory. The LLM cannot tell the difference.",[44,350,352],{"id":351},"how-it-works-under-the-hood","How it works under the hood",[28,354,355,356,359,360,363,364,367],{},"The cache key is ",[35,357,358],{},"sha256(tool_name + canonicalized_json_args)",". Arguments are re-serialized before hashing, so ",[35,361,362],{},"{\"a\":1, \"b\":2}"," and ",[35,365,366],{},"{\"b\":2,\"a\":1}"," hit the same cache entry. Whitespace differences don't matter.",[28,369,370],{},"The cache lives in-memory inside the agent pod. No Redis, no external dependencies, no infrastructure to deploy. It works with any LLM provider - Anthropic, OpenAI, Ollama, vLLM, whatever you run. The cache sits between the runner and the MCP dispatch, completely provider-agnostic.",[28,372,373,374,377],{},"Cache entries expire after ",[35,375,376],{},"ttlSeconds",". Default is 300 (5 minutes) - long enough to cover a reasoning loop, short enough that stale data isn't a real risk.",[44,379,381],{"id":380},"what-doesnt-get-cached","What doesn't get cached",[28,383,384],{},"Three things bypass the cache unconditionally:",[386,387,388,405,411],"ol",{},[389,390,391,394,395,319,398,319,401,404],"li",{},[52,392,393],{},"Tools on the exclude list."," ",[35,396,397],{},"store_result",[35,399,400],{},"send_email",[35,402,403],{},"create_ticket"," - anything that changes state.",[389,406,407,410],{},[52,408,409],{},"Failed calls."," If the MCP server returns an error, the error is not cached. The next call retries fresh.",[389,412,413,420],{},[52,414,415,416,419],{},"Servers without ",[35,417,418],{},"cache.enabled: true","."," Default is off. You opt in per server, not globally.",[44,422,424],{"id":423},"progressive-example","Progressive example",[28,426,427],{},"Start simple - cache everything on one server:",[67,429,431],{"className":69,"code":430,"language":71,"meta":72,"style":72},"tools:\n  mcp:\n    - name: knowledge-base\n      url: http:\u002F\u002Fkb-mcp.tools.svc:8080\n      cache:\n        enabled: true\n",[35,432,433,439,445,456,465,471],{"__ignoreMap":72},[76,434,435,437],{"class":78,"line":79},[76,436,90],{"class":89},[76,438,94],{"class":93},[76,440,441,443],{"class":78,"line":86},[76,442,100],{"class":89},[76,444,94],{"class":93},[76,446,447,449,451,453],{"class":78,"line":97},[76,448,108],{"class":93},[76,450,111],{"class":89},[76,452,114],{"class":93},[76,454,455],{"class":117},"knowledge-base\n",[76,457,458,460,462],{"class":78,"line":105},[76,459,124],{"class":89},[76,461,114],{"class":93},[76,463,464],{"class":117},"http:\u002F\u002Fkb-mcp.tools.svc:8080\n",[76,466,467,469],{"class":78,"line":121},[76,468,135],{"class":89},[76,470,94],{"class":93},[76,472,473,475,477],{"class":78,"line":132},[76,474,143],{"class":89},[76,476,114],{"class":93},[76,478,149],{"class":148},[28,480,481],{},"Defaults kick in: 300s TTL, no excludes. Every tool on that server gets cached.",[28,483,484],{},"Get specific - different TTLs per server, exclude writes:",[67,486,488],{"className":69,"code":487,"language":71,"meta":72,"style":72},"tools:\n  mcp:\n    - name: search\n      url: http:\u002F\u002Fsearch.tools.svc:8080\n      cache:\n        enabled: true\n        ttlSeconds: 600\n    - name: crm\n      url: http:\u002F\u002Fcrm-mcp.tools.svc:8080\n      cache:\n        enabled: true\n        ttlSeconds: 60\n        excludeTools:\n          - update_contact\n          - create_deal\n          - send_message\n",[35,489,490,496,502,512,521,527,535,543,554,563,569,578,588,595,603,611],{"__ignoreMap":72},[76,491,492,494],{"class":78,"line":79},[76,493,90],{"class":89},[76,495,94],{"class":93},[76,497,498,500],{"class":78,"line":86},[76,499,100],{"class":89},[76,501,94],{"class":93},[76,503,504,506,508,510],{"class":78,"line":97},[76,505,108],{"class":93},[76,507,111],{"class":89},[76,509,114],{"class":93},[76,511,118],{"class":117},[76,513,514,516,518],{"class":78,"line":105},[76,515,124],{"class":89},[76,517,114],{"class":93},[76,519,520],{"class":117},"http:\u002F\u002Fsearch.tools.svc:8080\n",[76,522,523,525],{"class":78,"line":121},[76,524,135],{"class":89},[76,526,94],{"class":93},[76,528,529,531,533],{"class":78,"line":132},[76,530,143],{"class":89},[76,532,114],{"class":93},[76,534,149],{"class":148},[76,536,537,539,541],{"class":78,"line":140},[76,538,155],{"class":89},[76,540,114],{"class":93},[76,542,160],{"class":148},[76,544,545,547,549,551],{"class":78,"line":152},[76,546,108],{"class":93},[76,548,111],{"class":89},[76,550,114],{"class":93},[76,552,553],{"class":117},"crm\n",[76,555,556,558,560],{"class":78,"line":163},[76,557,124],{"class":89},[76,559,114],{"class":93},[76,561,562],{"class":117},"http:\u002F\u002Fcrm-mcp.tools.svc:8080\n",[76,564,565,567],{"class":78,"line":171},[76,566,135],{"class":89},[76,568,94],{"class":93},[76,570,572,574,576],{"class":78,"line":571},11,[76,573,143],{"class":89},[76,575,114],{"class":93},[76,577,149],{"class":148},[76,579,581,583,585],{"class":78,"line":580},12,[76,582,155],{"class":89},[76,584,114],{"class":93},[76,586,587],{"class":148},"60\n",[76,589,591,593],{"class":78,"line":590},13,[76,592,166],{"class":89},[76,594,94],{"class":93},[76,596,598,600],{"class":78,"line":597},14,[76,599,174],{"class":93},[76,601,602],{"class":117},"update_contact\n",[76,604,606,608],{"class":78,"line":605},15,[76,607,174],{"class":93},[76,609,610],{"class":117},"create_deal\n",[76,612,614,616],{"class":78,"line":613},16,[76,615,174],{"class":93},[76,617,618],{"class":117},"send_message\n",[28,620,621],{},"Search results are stable for 10 minutes. CRM lookups get a shorter window because the data changes more often. Write operations always go through.",[44,623,625],{"id":624},"when-not-to-use-it","When not to use it",[28,627,628],{},"If your tools return different results for the same input (random sampling, current timestamp, live sensor data), caching will serve stale values. Don't enable it for those servers.",[28,630,631],{},"If your reasoning loops genuinely need fresh data on every iteration (polling for completion, watching for state changes), the TTL needs to be shorter than your poll interval - or just leave caching off for that server.",[44,633,635],{"id":634},"the-takeaway","The takeaway",[28,637,638],{},"80% of your agent's tool calls are waste. Three lines of YAML eliminate them. The model gets identical results, your MCP servers get 80% less traffic, and your agent finishes faster.",[28,640,641,642,644],{},"Try it: add ",[35,643,418],{}," to one MCP server and watch your tool call metrics drop.",[646,647,648],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":72,"searchDepth":86,"depth":86,"links":650},[651,652,653,654,655,656,657,658],{"id":46,"depth":86,"text":47},{"id":64,"depth":86,"text":65},{"id":193,"depth":86,"text":194},{"id":351,"depth":86,"text":352},{"id":380,"depth":86,"text":381},{"id":423,"depth":86,"text":424},{"id":624,"depth":86,"text":625},{"id":634,"depth":86,"text":635},null,"2026-04-29","kubeswarm's tool result cache cuts 80% of redundant MCP calls in reasoning loops - zero config changes to your tools, works with any provider.","md",{},true,"\u002Fblog\u002Ftool-result-caching",{"title":17,"description":661},"blog\u002Ftool-result-caching",[669,670,671,672],"cost-control","agents","mcp","deep-dive","o8WoMKTlVM5B7UUhlb6qCY8MmCsIE4WMz6qzAziPECo",1777484389913]