[{"data":1,"prerenderedAt":1975},["ShallowReactive",2],{"navigation":3,"/blog/mcp-article-complete":50},[4],{"title":5,"path":6,"stem":7,"children":8,"page":49},"Blog","/blog","blog",[9,13,17,21,25,29,33,37,41,45],{"title":10,"path":11,"stem":12},"Unlocking the Power of Django: A Developer-Friendly Architecture Guide","/blog/django-arhitecture","blog/01.django-arhitecture",{"title":14,"path":15,"stem":16},"Getting Started with Go: Why You Should Learn Golang","/blog/intro-go","blog/02.intro-go",{"title":18,"path":19,"stem":20},"Recursion in JavaScript: The Art of Functions Calling Themselves","/blog/recursion-js","blog/03.recursion-js",{"title":22,"path":23,"stem":24},"What Go Got Right and Wrong: A Thoughtful Look Back","/blog/golang-pro-and-cons","blog/04.golang-pro-and-cons",{"title":26,"path":27,"stem":28},"JavaScript Performance Optimization: A Practical Guide for Better Web Applications","/blog/js-perf","blog/05.js-perf",{"title":30,"path":31,"stem":32},"Understanding Go Slices: A Powerful Data Structure","/blog/go-slices-article","blog/06.go-slices-article",{"title":34,"path":35,"stem":36},"The Model Context Protocol (MCP): Giving AI \"Hands\"","/blog/mcp-article-complete","blog/07.mcp-article-complete",{"title":38,"path":39,"stem":40},"CSS Grid Mastery: Advanced Layout Techniques for Intermediate Developers","/blog/css-grid","blog/08.css-grid",{"title":42,"path":43,"stem":44},"Modern JavaScript: Mastering the Fetch API with Async/Await","/blog/fetch-api","blog/09.fetch-api",{"title":46,"path":47,"stem":48},"How to Use AWS for Cloud-Based Web Development","/blog/aws-webdev","blog/10.aws-webdev",false,[51,1970],{"id":52,"title":34,"author":53,"badge":59,"body":61,"date":1957,"description":1958,"extension":1959,"image":1960,"meta":1961,"navigation":202,"path":35,"readingTime":1962,"seo":1967,"stem":36,"tags":1968,"__hash__":1969},"blog/blog/07.mcp-article-complete.md",[54],{"name":55,"to":56,"avatar":57},"Norbert Br3tt","https://www.linkedin.com/in/norbert-brett/",{"src":58,"alt":55},"https://res.cloudinary.com/nbrett/image/upload/v1725625689/IMG_0698_d0nhun.jpg",{"label":60},"AI",{"type":62,"value":63,"toc":1940},"minimark",[64,69,73,76,79,84,87,94,100,111,114,123,126,130,133,138,141,237,240,244,247,290,299,305,309,312,358,376,380,383,420,423,427,430,434,1168,1179,1183,1186,1393,1396,1400,1403,1549,1552,1556,1559,1579,1713,1716,1720,1726,1732,1807,1813,1819,1884,1887,1891,1894,1897,1900,1903,1908,1936],[65,66,68],"h1",{"id":67},"mcp-give-your-ai-eyes-and-hands-not-just-a-keyboard","MCP: Give Your AI Eyes and Hands, Not Just a Keyboard",[70,71,72],"p",{},"Storytime: I was debugging a production issue at an unreasonable hour. The AI I was using was helpful — genuinely helpful — right up until the moment I needed it to check something in the database, verify an environment variable, or pull a stack trace from our error tracker. Each time, I had to stop, context-switch to another tab, copy something, paste it back, repeat.",[70,74,75],{},"The AI was smart. But it was blind.",[70,77,78],{},"The Model Context Protocol (MCP) fixes this. Instead of you manually shuttling context between your tools and your AI, MCP lets the AI reach out and grab what it needs directly — databases, browser sessions, error trackers, internal APIs, whatever you choose to expose. It's working in production today, and once you experience it, it's hard to go back.",[80,81,83],"h2",{"id":82},"whats-actually-happening-here","What's Actually Happening Here",[70,85,86],{},"MCP is a client-server protocol — but not in the web sense. Three pieces:",[70,88,89,93],{},[90,91,92],"strong",{},"MCP Hosts"," are AI applications that support the protocol. Claude Desktop, Cursor, and others. The host manages connections to MCP servers and decides when to invoke them.",[70,95,96,99],{},[90,97,98],{},"MCP Servers"," expose tools (functions the AI can call) and resources (data the AI can read). One server for your database, another for error tracking, another for your browser — each focused on a specific domain.",[70,101,102,105,106,110],{},[90,103,104],{},"The Protocol"," itself is JSON-RPC under the hood, but you don't need to know that. You just need to know: when you ask your AI a question, it can now go ",[107,108,109],"em",{},"get"," the answer instead of waiting for you to paste it in.",[70,112,113],{},"Here's what that looks like in practice:",[115,116,117,120],"blockquote",{},[70,118,119],{},"You ask: \"What's causing the error spike today?\"",[70,121,122],{},"The AI queries your Sentry MCP server → fetches recent issues → reads the relevant code → answers your question in plain language.",[70,124,125],{},"You see the answer. You never opened Sentry.",[80,127,129],{"id":128},"servers-you-can-use-right-now","Servers You Can Use Right Now",[70,131,132],{},"The ecosystem already has solid integrations for common dev workflows. Let me walk you through the ones I'd reach for first.",[134,135,137],"h3",{"id":136},"chrome-devtools-mcp","Chrome DevTools MCP",[70,139,140],{},"This one gives your AI control of a real browser. Instead of describing how to reproduce a bug, you can ask the AI to reproduce it.",[142,143,148],"pre",{"className":144,"code":145,"language":146,"meta":147,"style":147},"language-typescript shiki shiki-themes vitesse-dark","// Natural language prompt:\n\"Open the staging login page, try the test credentials, \nand report any console errors\"\n\n// What the AI actually does:\n// 1. Launches browser, navigates to URL\n// 2. Fills and submits the form\n// 3. Monitors the console\n// 4. Reports back what it found\n","typescript","",[149,150,151,160,175,197,204,213,219,225,231],"code",{"__ignoreMap":147},[152,153,156],"span",{"class":154,"line":155},"line",1,[152,157,159],{"class":158},"sux-A","// Natural language prompt:\n",[152,161,163,167,171],{"class":154,"line":162},2,[152,164,166],{"class":165},"sNJcY","\"",[152,168,170],{"class":169},"s7rlk","Open the staging login page, try the test credentials,",[152,172,174],{"class":173},"s6RL2"," \n",[152,176,178,182,185,188,191,194],{"class":154,"line":177},3,[152,179,181],{"class":180},"st-jp","and",[152,183,184],{"class":180}," report",[152,186,187],{"class":180}," any",[152,189,190],{"class":180}," console",[152,192,193],{"class":180}," errors",[152,195,196],{"class":165},"\"\n",[152,198,200],{"class":154,"line":199},4,[152,201,203],{"emptyLinePlaceholder":202},true,"\n",[152,205,207,210],{"class":154,"line":206},5,[152,208,209],{"class":169},"// What the AI actually does",[152,211,212],{"class":173},":\n",[152,214,216],{"class":154,"line":215},6,[152,217,218],{"class":158},"// 1. Launches browser, navigates to URL\n",[152,220,222],{"class":154,"line":221},7,[152,223,224],{"class":158},"// 2. Fills and submits the form\n",[152,226,228],{"class":154,"line":227},8,[152,229,230],{"class":158},"// 3. Monitors the console\n",[152,232,234],{"class":154,"line":233},9,[152,235,236],{"class":158},"// 4. Reports back what it found\n",[70,238,239],{},"I personally find this most useful for CSS debugging. \"Inspect that button, check the computed styles, figure out why it's 4px off on mobile\" — instead of doing it yourself across DevTools and a chat window.",[134,241,243],{"id":242},"sentry-mcp","Sentry MCP",[70,245,246],{},"Error tracking becomes conversational.",[142,248,250],{"className":144,"code":249,"language":146,"meta":147,"style":147},"// You ask:\n\"Show me unresolved database errors from the API service, last 24 hours\"\n\n// The AI:\n// - Translates to Sentry API calls\n// - Filters by project, timeframe, error type\n// - Returns formatted stack traces\n",[149,251,252,257,266,270,275,280,285],{"__ignoreMap":147},[152,253,254],{"class":154,"line":155},[152,255,256],{"class":158},"// You ask:\n",[152,258,259,261,264],{"class":154,"line":162},[152,260,166],{"class":165},[152,262,263],{"class":169},"Show me unresolved database errors from the API service, last 24 hours",[152,265,196],{"class":165},[152,267,268],{"class":154,"line":177},[152,269,203],{"emptyLinePlaceholder":202},[152,271,272],{"class":154,"line":199},[152,273,274],{"class":158},"// The AI:\n",[152,276,277],{"class":154,"line":206},[152,278,279],{"class":158},"// - Translates to Sentry API calls\n",[152,281,282],{"class":154,"line":215},[152,283,284],{"class":158},"// - Filters by project, timeframe, error type\n",[152,286,287],{"class":154,"line":221},[152,288,289],{"class":158},"// - Returns formatted stack traces\n",[70,291,292,293,295,296,298],{},"The real payoff: the AI can fetch an error from Sentry ",[107,294,181],{}," open the relevant source file ",[107,297,181],{}," suggest a fix — all in one shot. That's the workflow that feels like magic the first time.",[70,300,301,304],{},[90,302,303],{},"Setup tip",": Use a read-only Sentry API token. There's no reason your AI needs write access here.",[134,306,308],{"id":307},"postgres-mcp","Postgres MCP",[70,310,311],{},"The AI understands your schema without you pasting it in every session.",[142,313,315],{"className":144,"code":314,"language":146,"meta":147,"style":147},"// You ask:\n\"How many users signed up last week, grouped by referral source?\"\n\n// The AI:\n// 1. Checks the schema to find the right tables and columns\n// 2. Writes the SQL\n// 3. Runs it\n// 4. Formats the results\n",[149,316,317,321,330,334,338,343,348,353],{"__ignoreMap":147},[152,318,319],{"class":154,"line":155},[152,320,256],{"class":158},[152,322,323,325,328],{"class":154,"line":162},[152,324,166],{"class":165},[152,326,327],{"class":169},"How many users signed up last week, grouped by referral source?",[152,329,196],{"class":165},[152,331,332],{"class":154,"line":177},[152,333,203],{"emptyLinePlaceholder":202},[152,335,336],{"class":154,"line":199},[152,337,274],{"class":158},[152,339,340],{"class":154,"line":206},[152,341,342],{"class":158},"// 1. Checks the schema to find the right tables and columns\n",[152,344,345],{"class":154,"line":215},[152,346,347],{"class":158},"// 2. Writes the SQL\n",[152,349,350],{"class":154,"line":221},[152,351,352],{"class":158},"// 3. Runs it\n",[152,354,355],{"class":154,"line":227},[152,356,357],{"class":158},"// 4. Formats the results\n",[70,359,360,363,364,367,368,371,372,375],{},[90,361,362],{},"Important",": Configure this with read-only credentials. Seriously. A ",[149,365,366],{},"SELECT","-only database user is five minutes to set up and means you'll never have a bad day where the AI runs a ",[149,369,370],{},"DELETE"," with a missing ",[149,373,374],{},"WHERE"," clause.",[134,377,379],{"id":378},"stripe-mcp","Stripe MCP",[70,381,382],{},"Customer and payment queries in plain language — especially useful if your support team needs Stripe access without learning the dashboard.",[142,384,386],{"className":144,"code":385,"language":146,"meta":147,"style":147},"// Support workflow:\n\"Does user@example.com have an active subscription, and when does it renew?\"\n\n// Dev workflow:\n\"Create a test customer with a monthly Pro plan subscription\"\n",[149,387,388,393,402,406,411],{"__ignoreMap":147},[152,389,390],{"class":154,"line":155},[152,391,392],{"class":158},"// Support workflow:\n",[152,394,395,397,400],{"class":154,"line":162},[152,396,166],{"class":165},[152,398,399],{"class":169},"Does user@example.com have an active subscription, and when does it renew?",[152,401,196],{"class":165},[152,403,404],{"class":154,"line":177},[152,405,203],{"emptyLinePlaceholder":202},[152,407,408],{"class":154,"line":199},[152,409,410],{"class":158},"// Dev workflow:\n",[152,412,413,415,418],{"class":154,"line":206},[152,414,166],{"class":165},[152,416,417],{"class":169},"Create a test customer with a monthly Pro plan subscription",[152,419,196],{"class":165},[70,421,422],{},"Use restricted API keys. Test mode and live mode should be separate MCP configurations.",[80,424,426],{"id":425},"building-your-own-mcp-server","Building Your Own MCP Server",[70,428,429],{},"When the existing servers don't cover your use case — an internal API, a proprietary tool, a custom database — building one is more approachable than it sounds. Let me show you the shape of it.",[134,431,433],{"id":432},"the-basic-structure","The Basic Structure",[142,435,437],{"className":144,"code":436,"language":146,"meta":147,"style":147},"import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { CallToolRequestSchema, ListToolsRequestSchema } from \"@modelcontextprotocol/sdk/types.js\";\n\nconst server = new Server(\n  { name: \"my-server\", version: \"1.0.0\" },\n  { capabilities: { tools: {} } }\n);\n\n// Tell the AI what tools are available\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n  tools: [\n    {\n      name: \"search_users\",\n      description: \"Searches users by email or username\",\n      inputSchema: {\n        type: \"object\",\n        properties: {\n          query: { type: \"string\", description: \"Search term\" },\n          limit: { type: \"number\", default: 10 }\n        },\n        required: [\"query\"],\n      },\n    },\n  ],\n}));\n\n// Handle the actual calls\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n  const { name, arguments: args } = request.params;\n\n  if (name === \"search_users\") {\n    const users = await database.users.search(args.query, args.limit ?? 10);\n    return {\n      content: [{ type: \"text\", text: JSON.stringify(users, null, 2) }],\n    };\n  }\n\n  throw new Error(`Unknown tool: ${name}`);\n});\n\n// Connect and run\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n",[149,438,439,469,491,519,523,545,582,598,603,607,613,644,653,659,677,694,703,720,728,764,797,803,822,828,834,840,846,851,857,889,926,931,954,1005,1013,1064,1070,1076,1081,1113,1119,1124,1130,1148],{"__ignoreMap":147},[152,440,441,445,449,452,455,458,461,464,466],{"class":154,"line":155},[152,442,444],{"class":443},"s3QIE","import",[152,446,448],{"class":447},"s_pn2"," {",[152,450,451],{"class":180}," Server",[152,453,454],{"class":447}," }",[152,456,457],{"class":443}," from",[152,459,460],{"class":165}," \"",[152,462,463],{"class":169},"@modelcontextprotocol/sdk/server/index.js",[152,465,166],{"class":165},[152,467,468],{"class":447},";\n",[152,470,471,473,475,478,480,482,484,487,489],{"class":154,"line":162},[152,472,444],{"class":443},[152,474,448],{"class":447},[152,476,477],{"class":180}," StdioServerTransport",[152,479,454],{"class":447},[152,481,457],{"class":443},[152,483,460],{"class":165},[152,485,486],{"class":169},"@modelcontextprotocol/sdk/server/stdio.js",[152,488,166],{"class":165},[152,490,468],{"class":447},[152,492,493,495,497,500,503,506,508,510,512,515,517],{"class":154,"line":177},[152,494,444],{"class":443},[152,496,448],{"class":447},[152,498,499],{"class":180}," CallToolRequestSchema",[152,501,502],{"class":447},",",[152,504,505],{"class":180}," ListToolsRequestSchema",[152,507,454],{"class":447},[152,509,457],{"class":443},[152,511,460],{"class":165},[152,513,514],{"class":169},"@modelcontextprotocol/sdk/types.js",[152,516,166],{"class":165},[152,518,468],{"class":447},[152,520,521],{"class":154,"line":199},[152,522,203],{"emptyLinePlaceholder":202},[152,524,525,529,532,535,538,542],{"class":154,"line":206},[152,526,528],{"class":527},"s_wWq","const ",[152,530,531],{"class":180},"server",[152,533,534],{"class":447}," =",[152,536,537],{"class":527}," new ",[152,539,541],{"class":540},"sCK9x","Server",[152,543,544],{"class":447},"(\n",[152,546,547,550,554,557,559,562,564,567,570,572,574,577,579],{"class":154,"line":215},[152,548,549],{"class":447},"  { ",[152,551,553],{"class":552},"sm68I","name",[152,555,556],{"class":447},": ",[152,558,166],{"class":165},[152,560,561],{"class":169},"my-server",[152,563,166],{"class":165},[152,565,566],{"class":447},", ",[152,568,569],{"class":552},"version",[152,571,556],{"class":447},[152,573,166],{"class":165},[152,575,576],{"class":169},"1.0.0",[152,578,166],{"class":165},[152,580,581],{"class":447}," },\n",[152,583,584,586,589,592,595],{"class":154,"line":221},[152,585,549],{"class":447},[152,587,588],{"class":552},"capabilities",[152,590,591],{"class":447},": { ",[152,593,594],{"class":552},"tools",[152,596,597],{"class":447},": {} } }\n",[152,599,600],{"class":154,"line":227},[152,601,602],{"class":447},");\n",[152,604,605],{"class":154,"line":233},[152,606,203],{"emptyLinePlaceholder":202},[152,608,610],{"class":154,"line":609},10,[152,611,612],{"class":158},"// Tell the AI what tools are available\n",[152,614,616,618,621,624,627,630,632,635,638,641],{"class":154,"line":615},11,[152,617,531],{"class":180},[152,619,620],{"class":447},".",[152,622,623],{"class":540},"setRequestHandler",[152,625,626],{"class":447},"(",[152,628,629],{"class":180},"ListToolsRequestSchema",[152,631,502],{"class":447},[152,633,634],{"class":527}," async",[152,636,637],{"class":447}," ()",[152,639,640],{"class":447}," =>",[152,642,643],{"class":447}," ({\n",[152,645,647,650],{"class":154,"line":646},12,[152,648,649],{"class":552},"  tools",[152,651,652],{"class":447},": [\n",[152,654,656],{"class":154,"line":655},13,[152,657,658],{"class":447},"    {\n",[152,660,662,665,667,669,672,674],{"class":154,"line":661},14,[152,663,664],{"class":552},"      name",[152,666,556],{"class":447},[152,668,166],{"class":165},[152,670,671],{"class":169},"search_users",[152,673,166],{"class":165},[152,675,676],{"class":447},",\n",[152,678,680,683,685,687,690,692],{"class":154,"line":679},15,[152,681,682],{"class":552},"      description",[152,684,556],{"class":447},[152,686,166],{"class":165},[152,688,689],{"class":169},"Searches users by email or username",[152,691,166],{"class":165},[152,693,676],{"class":447},[152,695,697,700],{"class":154,"line":696},16,[152,698,699],{"class":552},"      inputSchema",[152,701,702],{"class":447},": {\n",[152,704,706,709,711,713,716,718],{"class":154,"line":705},17,[152,707,708],{"class":552},"        type",[152,710,556],{"class":447},[152,712,166],{"class":165},[152,714,715],{"class":169},"object",[152,717,166],{"class":165},[152,719,676],{"class":447},[152,721,723,726],{"class":154,"line":722},18,[152,724,725],{"class":552},"        properties",[152,727,702],{"class":447},[152,729,731,734,736,739,741,743,746,748,750,753,755,757,760,762],{"class":154,"line":730},19,[152,732,733],{"class":552},"          query",[152,735,591],{"class":447},[152,737,738],{"class":552},"type",[152,740,556],{"class":447},[152,742,166],{"class":165},[152,744,745],{"class":169},"string",[152,747,166],{"class":165},[152,749,566],{"class":447},[152,751,752],{"class":552},"description",[152,754,556],{"class":447},[152,756,166],{"class":165},[152,758,759],{"class":169},"Search term",[152,761,166],{"class":165},[152,763,581],{"class":447},[152,765,767,770,772,774,776,778,781,783,785,788,790,794],{"class":154,"line":766},20,[152,768,769],{"class":552},"          limit",[152,771,591],{"class":447},[152,773,738],{"class":552},[152,775,556],{"class":447},[152,777,166],{"class":165},[152,779,780],{"class":169},"number",[152,782,166],{"class":165},[152,784,566],{"class":447},[152,786,787],{"class":552},"default",[152,789,556],{"class":447},[152,791,793],{"class":792},"sxA9i","10",[152,795,796],{"class":447}," }\n",[152,798,800],{"class":154,"line":799},21,[152,801,802],{"class":447},"        },\n",[152,804,806,809,812,814,817,819],{"class":154,"line":805},22,[152,807,808],{"class":552},"        required",[152,810,811],{"class":447},": [",[152,813,166],{"class":165},[152,815,816],{"class":169},"query",[152,818,166],{"class":165},[152,820,821],{"class":447},"],\n",[152,823,825],{"class":154,"line":824},23,[152,826,827],{"class":447},"      },\n",[152,829,831],{"class":154,"line":830},24,[152,832,833],{"class":447},"    },\n",[152,835,837],{"class":154,"line":836},25,[152,838,839],{"class":447},"  ],\n",[152,841,843],{"class":154,"line":842},26,[152,844,845],{"class":447},"}));\n",[152,847,849],{"class":154,"line":848},27,[152,850,203],{"emptyLinePlaceholder":202},[152,852,854],{"class":154,"line":853},28,[152,855,856],{"class":158},"// Handle the actual calls\n",[152,858,860,862,864,866,868,871,873,875,878,881,884,886],{"class":154,"line":859},29,[152,861,531],{"class":180},[152,863,620],{"class":447},[152,865,623],{"class":540},[152,867,626],{"class":447},[152,869,870],{"class":180},"CallToolRequestSchema",[152,872,502],{"class":447},[152,874,634],{"class":527},[152,876,877],{"class":447}," (",[152,879,880],{"class":180},"request",[152,882,883],{"class":447},")",[152,885,640],{"class":447},[152,887,888],{"class":447}," {\n",[152,890,892,895,898,901,903,906,909,912,914,916,919,921,924],{"class":154,"line":891},30,[152,893,894],{"class":527},"  const ",[152,896,897],{"class":447},"{",[152,899,900],{"class":180}," name",[152,902,502],{"class":447},[152,904,905],{"class":180}," arguments",[152,907,908],{"class":447},":",[152,910,911],{"class":180}," args",[152,913,454],{"class":447},[152,915,534],{"class":447},[152,917,918],{"class":180}," request",[152,920,620],{"class":447},[152,922,923],{"class":180},"params",[152,925,468],{"class":447},[152,927,929],{"class":154,"line":928},31,[152,930,203],{"emptyLinePlaceholder":202},[152,932,934,937,939,941,944,946,948,950,952],{"class":154,"line":933},32,[152,935,936],{"class":443},"  if",[152,938,877],{"class":447},[152,940,553],{"class":180},[152,942,943],{"class":527}," ===",[152,945,460],{"class":165},[152,947,671],{"class":169},[152,949,166],{"class":165},[152,951,883],{"class":447},[152,953,888],{"class":447},[152,955,957,960,963,965,968,971,973,975,977,980,982,985,987,989,991,993,995,998,1001,1003],{"class":154,"line":956},33,[152,958,959],{"class":527},"    const ",[152,961,962],{"class":180},"users",[152,964,534],{"class":447},[152,966,967],{"class":443}," await",[152,969,970],{"class":180}," database",[152,972,620],{"class":447},[152,974,962],{"class":180},[152,976,620],{"class":447},[152,978,979],{"class":540},"search",[152,981,626],{"class":447},[152,983,984],{"class":180},"args",[152,986,620],{"class":447},[152,988,816],{"class":180},[152,990,502],{"class":447},[152,992,911],{"class":180},[152,994,620],{"class":447},[152,996,997],{"class":180},"limit",[152,999,1000],{"class":527}," ?? ",[152,1002,793],{"class":792},[152,1004,602],{"class":447},[152,1006,1008,1011],{"class":154,"line":1007},34,[152,1009,1010],{"class":443},"    return",[152,1012,888],{"class":447},[152,1014,1016,1019,1022,1024,1026,1028,1031,1033,1035,1037,1039,1042,1044,1047,1049,1051,1053,1056,1058,1061],{"class":154,"line":1015},35,[152,1017,1018],{"class":552},"      content",[152,1020,1021],{"class":447},": [{ ",[152,1023,738],{"class":552},[152,1025,556],{"class":447},[152,1027,166],{"class":165},[152,1029,1030],{"class":169},"text",[152,1032,166],{"class":165},[152,1034,566],{"class":447},[152,1036,1030],{"class":552},[152,1038,556],{"class":447},[152,1040,1041],{"class":180},"JSON",[152,1043,620],{"class":447},[152,1045,1046],{"class":540},"stringify",[152,1048,626],{"class":447},[152,1050,962],{"class":180},[152,1052,566],{"class":447},[152,1054,1055],{"class":527},"null",[152,1057,566],{"class":447},[152,1059,1060],{"class":792},"2",[152,1062,1063],{"class":447},") }],\n",[152,1065,1067],{"class":154,"line":1066},36,[152,1068,1069],{"class":447},"    };\n",[152,1071,1073],{"class":154,"line":1072},37,[152,1074,1075],{"class":447},"  }\n",[152,1077,1079],{"class":154,"line":1078},38,[152,1080,203],{"emptyLinePlaceholder":202},[152,1082,1084,1087,1090,1093,1095,1098,1101,1104,1106,1109,1111],{"class":154,"line":1083},39,[152,1085,1086],{"class":443},"  throw",[152,1088,1089],{"class":527}," new",[152,1091,1092],{"class":540}," Error",[152,1094,626],{"class":447},[152,1096,1097],{"class":165},"`",[152,1099,1100],{"class":169},"Unknown tool: ",[152,1102,1103],{"class":443},"${",[152,1105,553],{"class":169},[152,1107,1108],{"class":443},"}",[152,1110,1097],{"class":165},[152,1112,602],{"class":447},[152,1114,1116],{"class":154,"line":1115},40,[152,1117,1118],{"class":447},"});\n",[152,1120,1122],{"class":154,"line":1121},41,[152,1123,203],{"emptyLinePlaceholder":202},[152,1125,1127],{"class":154,"line":1126},42,[152,1128,1129],{"class":158},"// Connect and run\n",[152,1131,1133,1135,1138,1140,1142,1145],{"class":154,"line":1132},43,[152,1134,528],{"class":527},[152,1136,1137],{"class":180},"transport",[152,1139,534],{"class":447},[152,1141,537],{"class":527},[152,1143,1144],{"class":540},"StdioServerTransport",[152,1146,1147],{"class":447},"();\n",[152,1149,1151,1154,1157,1159,1162,1164,1166],{"class":154,"line":1150},44,[152,1152,1153],{"class":443},"await",[152,1155,1156],{"class":180}," server",[152,1158,620],{"class":447},[152,1160,1161],{"class":540},"connect",[152,1163,626],{"class":447},[152,1165,1137],{"class":180},[152,1167,602],{"class":447},[70,1169,1170,1171,1174,1175,1178],{},"That's the whole pattern. Define what tools exist (",[149,1172,1173],{},"ListTools","), handle when they're called (",[149,1176,1177],{},"CallTool","), return structured results.",[134,1180,1182],{"id":1181},"add-validation-always","Add Validation — Always",[70,1184,1185],{},"Before you ship anything, add Zod validation on your inputs. The AI sends data in good faith, but good faith isn't a type system.",[142,1187,1189],{"className":144,"code":1188,"language":146,"meta":147,"style":147},"import { z } from \"zod\";\n\nconst SearchSchema = z.object({\n  query: z.string().min(1).max(100),\n  limit: z.number().int().min(1).max(100).default(10),\n});\n\n// In your handler:\nconst validated = SearchSchema.parse(args);\nconst users = await database.users.search(validated.query, validated.limit);\n",[149,1190,1191,1213,1217,1235,1274,1318,1322,1326,1331,1354],{"__ignoreMap":147},[152,1192,1193,1195,1197,1200,1202,1204,1206,1209,1211],{"class":154,"line":155},[152,1194,444],{"class":443},[152,1196,448],{"class":447},[152,1198,1199],{"class":180}," z",[152,1201,454],{"class":447},[152,1203,457],{"class":443},[152,1205,460],{"class":165},[152,1207,1208],{"class":169},"zod",[152,1210,166],{"class":165},[152,1212,468],{"class":447},[152,1214,1215],{"class":154,"line":162},[152,1216,203],{"emptyLinePlaceholder":202},[152,1218,1219,1221,1224,1226,1228,1230,1232],{"class":154,"line":177},[152,1220,528],{"class":527},[152,1222,1223],{"class":180},"SearchSchema",[152,1225,534],{"class":447},[152,1227,1199],{"class":180},[152,1229,620],{"class":447},[152,1231,715],{"class":540},[152,1233,1234],{"class":447},"({\n",[152,1236,1237,1240,1242,1245,1247,1249,1252,1255,1257,1260,1263,1266,1268,1271],{"class":154,"line":199},[152,1238,1239],{"class":552},"  query",[152,1241,556],{"class":447},[152,1243,1244],{"class":180},"z",[152,1246,620],{"class":447},[152,1248,745],{"class":540},[152,1250,1251],{"class":447},"().",[152,1253,1254],{"class":540},"min",[152,1256,626],{"class":447},[152,1258,1259],{"class":792},"1",[152,1261,1262],{"class":447},").",[152,1264,1265],{"class":540},"max",[152,1267,626],{"class":447},[152,1269,1270],{"class":792},"100",[152,1272,1273],{"class":447},"),\n",[152,1275,1276,1279,1281,1283,1285,1287,1289,1292,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312,1314,1316],{"class":154,"line":206},[152,1277,1278],{"class":552},"  limit",[152,1280,556],{"class":447},[152,1282,1244],{"class":180},[152,1284,620],{"class":447},[152,1286,780],{"class":540},[152,1288,1251],{"class":447},[152,1290,1291],{"class":540},"int",[152,1293,1251],{"class":447},[152,1295,1254],{"class":540},[152,1297,626],{"class":447},[152,1299,1259],{"class":792},[152,1301,1262],{"class":447},[152,1303,1265],{"class":540},[152,1305,626],{"class":447},[152,1307,1270],{"class":792},[152,1309,1262],{"class":447},[152,1311,787],{"class":540},[152,1313,626],{"class":447},[152,1315,793],{"class":792},[152,1317,1273],{"class":447},[152,1319,1320],{"class":154,"line":215},[152,1321,1118],{"class":447},[152,1323,1324],{"class":154,"line":221},[152,1325,203],{"emptyLinePlaceholder":202},[152,1327,1328],{"class":154,"line":227},[152,1329,1330],{"class":158},"// In your handler:\n",[152,1332,1333,1335,1338,1340,1343,1345,1348,1350,1352],{"class":154,"line":233},[152,1334,528],{"class":527},[152,1336,1337],{"class":180},"validated",[152,1339,534],{"class":447},[152,1341,1342],{"class":180}," SearchSchema",[152,1344,620],{"class":447},[152,1346,1347],{"class":540},"parse",[152,1349,626],{"class":447},[152,1351,984],{"class":180},[152,1353,602],{"class":447},[152,1355,1356,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1378,1380,1382,1384,1387,1389,1391],{"class":154,"line":609},[152,1357,528],{"class":527},[152,1359,962],{"class":180},[152,1361,534],{"class":447},[152,1363,967],{"class":443},[152,1365,970],{"class":180},[152,1367,620],{"class":447},[152,1369,962],{"class":180},[152,1371,620],{"class":447},[152,1373,979],{"class":540},[152,1375,626],{"class":447},[152,1377,1337],{"class":180},[152,1379,620],{"class":447},[152,1381,816],{"class":180},[152,1383,502],{"class":447},[152,1385,1386],{"class":180}," validated",[152,1388,620],{"class":447},[152,1390,997],{"class":180},[152,1392,602],{"class":447},[70,1394,1395],{},"Clear error messages when validation fails make debugging significantly less painful.",[134,1397,1399],{"id":1398},"add-resources-for-dynamic-docs","Add Resources for Dynamic Docs",[70,1401,1402],{},"Resources are how you give the AI access to reference data — API documentation, configuration, anything that changes over time.",[142,1404,1406],{"className":144,"code":1405,"language":146,"meta":147,"style":147},"server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n  if (request.params.uri === \"docs://api/endpoints\") {\n    const docs = await loadApiDocs(); // fetches current state\n    return {\n      contents: [{ uri: request.params.uri, mimeType: \"text/markdown\", text: docs }],\n    };\n  }\n});\n",[149,1407,1408,1435,1465,1485,1491,1537,1541,1545],{"__ignoreMap":147},[152,1409,1410,1412,1414,1416,1418,1421,1423,1425,1427,1429,1431,1433],{"class":154,"line":155},[152,1411,531],{"class":180},[152,1413,620],{"class":447},[152,1415,623],{"class":540},[152,1417,626],{"class":447},[152,1419,1420],{"class":180},"ReadResourceRequestSchema",[152,1422,502],{"class":447},[152,1424,634],{"class":527},[152,1426,877],{"class":447},[152,1428,880],{"class":180},[152,1430,883],{"class":447},[152,1432,640],{"class":447},[152,1434,888],{"class":447},[152,1436,1437,1439,1441,1443,1445,1447,1449,1452,1454,1456,1459,1461,1463],{"class":154,"line":162},[152,1438,936],{"class":443},[152,1440,877],{"class":447},[152,1442,880],{"class":180},[152,1444,620],{"class":447},[152,1446,923],{"class":180},[152,1448,620],{"class":447},[152,1450,1451],{"class":180},"uri",[152,1453,943],{"class":527},[152,1455,460],{"class":165},[152,1457,1458],{"class":169},"docs://api/endpoints",[152,1460,166],{"class":165},[152,1462,883],{"class":447},[152,1464,888],{"class":447},[152,1466,1467,1469,1472,1474,1476,1479,1482],{"class":154,"line":177},[152,1468,959],{"class":527},[152,1470,1471],{"class":180},"docs",[152,1473,534],{"class":447},[152,1475,967],{"class":443},[152,1477,1478],{"class":540}," loadApiDocs",[152,1480,1481],{"class":447},"();",[152,1483,1484],{"class":158}," // fetches current state\n",[152,1486,1487,1489],{"class":154,"line":199},[152,1488,1010],{"class":443},[152,1490,888],{"class":447},[152,1492,1493,1496,1498,1500,1502,1504,1506,1508,1510,1512,1514,1517,1519,1521,1524,1526,1528,1530,1532,1534],{"class":154,"line":206},[152,1494,1495],{"class":552},"      contents",[152,1497,1021],{"class":447},[152,1499,1451],{"class":552},[152,1501,556],{"class":447},[152,1503,880],{"class":180},[152,1505,620],{"class":447},[152,1507,923],{"class":180},[152,1509,620],{"class":447},[152,1511,1451],{"class":180},[152,1513,566],{"class":447},[152,1515,1516],{"class":552},"mimeType",[152,1518,556],{"class":447},[152,1520,166],{"class":165},[152,1522,1523],{"class":169},"text/markdown",[152,1525,166],{"class":165},[152,1527,566],{"class":447},[152,1529,1030],{"class":552},[152,1531,556],{"class":447},[152,1533,1471],{"class":180},[152,1535,1536],{"class":447}," }],\n",[152,1538,1539],{"class":154,"line":215},[152,1540,1069],{"class":447},[152,1542,1543],{"class":154,"line":221},[152,1544,1075],{"class":447},[152,1546,1547],{"class":154,"line":227},[152,1548,1118],{"class":447},[70,1550,1551],{},"This is one of my favorite MCP patterns — documentation that's always current because it's fetched dynamically, not copy-pasted once and forgotten.",[134,1553,1555],{"id":1554},"connecting-it-to-claude-desktop","Connecting It to Claude Desktop",[70,1557,1558],{},"Edit the config file:",[1560,1561,1562,1571],"ul",{},[1563,1564,1565,556,1568],"li",{},[90,1566,1567],{},"macOS",[149,1569,1570],{},"~/Library/Application Support/Claude/claude_desktop_config.json",[1563,1572,1573,556,1576],{},[90,1574,1575],{},"Windows",[149,1577,1578],{},"%APPDATA%/Claude/claude_desktop_config.json",[142,1580,1584],{"className":1581,"code":1582,"language":1583,"meta":147,"style":147},"language-json shiki shiki-themes vitesse-dark","{\n  \"mcpServers\": {\n    \"my-server\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/server/build/index.js\"],\n      \"env\": {\n        \"DATABASE_URL\": \"postgresql://localhost:5432/mydb\"\n      }\n    }\n  }\n}\n","json",[149,1585,1586,1591,1606,1619,1640,1662,1675,1694,1699,1704,1708],{"__ignoreMap":147},[152,1587,1588],{"class":154,"line":155},[152,1589,1590],{"class":447},"{\n",[152,1592,1593,1597,1600,1602,1604],{"class":154,"line":162},[152,1594,1596],{"class":1595},"s6USN","  \"",[152,1598,1599],{"class":552},"mcpServers",[152,1601,166],{"class":1595},[152,1603,908],{"class":447},[152,1605,888],{"class":447},[152,1607,1608,1611,1613,1615,1617],{"class":154,"line":177},[152,1609,1610],{"class":1595},"    \"",[152,1612,561],{"class":552},[152,1614,166],{"class":1595},[152,1616,908],{"class":447},[152,1618,888],{"class":447},[152,1620,1621,1624,1627,1629,1631,1633,1636,1638],{"class":154,"line":199},[152,1622,1623],{"class":1595},"      \"",[152,1625,1626],{"class":552},"command",[152,1628,166],{"class":1595},[152,1630,908],{"class":447},[152,1632,460],{"class":165},[152,1634,1635],{"class":169},"node",[152,1637,166],{"class":165},[152,1639,676],{"class":447},[152,1641,1642,1644,1646,1648,1650,1653,1655,1658,1660],{"class":154,"line":206},[152,1643,1623],{"class":1595},[152,1645,984],{"class":552},[152,1647,166],{"class":1595},[152,1649,908],{"class":447},[152,1651,1652],{"class":447}," [",[152,1654,166],{"class":165},[152,1656,1657],{"class":169},"/path/to/server/build/index.js",[152,1659,166],{"class":165},[152,1661,821],{"class":447},[152,1663,1664,1666,1669,1671,1673],{"class":154,"line":215},[152,1665,1623],{"class":1595},[152,1667,1668],{"class":552},"env",[152,1670,166],{"class":1595},[152,1672,908],{"class":447},[152,1674,888],{"class":447},[152,1676,1677,1680,1683,1685,1687,1689,1692],{"class":154,"line":221},[152,1678,1679],{"class":1595},"        \"",[152,1681,1682],{"class":552},"DATABASE_URL",[152,1684,166],{"class":1595},[152,1686,908],{"class":447},[152,1688,460],{"class":165},[152,1690,1691],{"class":169},"postgresql://localhost:5432/mydb",[152,1693,196],{"class":165},[152,1695,1696],{"class":154,"line":227},[152,1697,1698],{"class":447},"      }\n",[152,1700,1701],{"class":154,"line":233},[152,1702,1703],{"class":447},"    }\n",[152,1705,1706],{"class":154,"line":609},[152,1707,1075],{"class":447},[152,1709,1710],{"class":154,"line":615},[152,1711,1712],{"class":447},"}\n",[70,1714,1715],{},"Restart Claude Desktop. Your tools are now available.",[80,1717,1719],{"id":1718},"security-a-few-rules-that-matter","Security: A Few Rules That Matter",[70,1721,1722,1725],{},[90,1723,1724],{},"Read-only by default."," Every database connection your MCP server makes should use a read-only user unless you've explicitly decided otherwise. This applies to Postgres, your internal APIs, everything.",[70,1727,1728,1731],{},[90,1729,1730],{},"Validate inputs."," I said it above but I'll say it again — always validate, even though the inputs come from AI. Especially for anything destructive:",[142,1733,1735],{"className":144,"code":1734,"language":146,"meta":147,"style":147},"const DeleteSchema = z.object({\n  userId: z.number().int().positive(),\n  confirmationToken: z.string().uuid(), // require explicit confirmation\n});\n",[149,1736,1737,1754,1779,1803],{"__ignoreMap":147},[152,1738,1739,1741,1744,1746,1748,1750,1752],{"class":154,"line":155},[152,1740,528],{"class":527},[152,1742,1743],{"class":180},"DeleteSchema",[152,1745,534],{"class":447},[152,1747,1199],{"class":180},[152,1749,620],{"class":447},[152,1751,715],{"class":540},[152,1753,1234],{"class":447},[152,1755,1756,1759,1761,1763,1765,1767,1769,1771,1773,1776],{"class":154,"line":162},[152,1757,1758],{"class":552},"  userId",[152,1760,556],{"class":447},[152,1762,1244],{"class":180},[152,1764,620],{"class":447},[152,1766,780],{"class":540},[152,1768,1251],{"class":447},[152,1770,1291],{"class":540},[152,1772,1251],{"class":447},[152,1774,1775],{"class":540},"positive",[152,1777,1778],{"class":447},"(),\n",[152,1780,1781,1784,1786,1788,1790,1792,1794,1797,1800],{"class":154,"line":177},[152,1782,1783],{"class":552},"  confirmationToken",[152,1785,556],{"class":447},[152,1787,1244],{"class":180},[152,1789,620],{"class":447},[152,1791,745],{"class":540},[152,1793,1251],{"class":447},[152,1795,1796],{"class":540},"uuid",[152,1798,1799],{"class":447},"(), ",[152,1801,1802],{"class":158},"// require explicit confirmation\n",[152,1804,1805],{"class":154,"line":199},[152,1806,1118],{"class":447},[70,1808,1809,1812],{},[90,1810,1811],{},"Separate dev from prod."," Use different MCP configurations for different environments. Point your day-to-day work at your development database. Only connect to production when you specifically need it, and never with write access unless there's no alternative.",[70,1814,1815,1818],{},[90,1816,1817],{},"Log everything."," Build an audit trail from the start:",[142,1820,1822],{"className":144,"code":1821,"language":146,"meta":147,"style":147},"await auditLog.record({\n  timestamp: new Date().toISOString(),\n  tool: name,\n  arguments: args,\n});\n",[149,1823,1824,1838,1858,1869,1880],{"__ignoreMap":147},[152,1825,1826,1828,1831,1833,1836],{"class":154,"line":155},[152,1827,1153],{"class":443},[152,1829,1830],{"class":180}," auditLog",[152,1832,620],{"class":447},[152,1834,1835],{"class":540},"record",[152,1837,1234],{"class":447},[152,1839,1840,1843,1845,1848,1851,1853,1856],{"class":154,"line":162},[152,1841,1842],{"class":552},"  timestamp",[152,1844,556],{"class":447},[152,1846,1847],{"class":527},"new",[152,1849,1850],{"class":540}," Date",[152,1852,1251],{"class":447},[152,1854,1855],{"class":540},"toISOString",[152,1857,1778],{"class":447},[152,1859,1860,1863,1865,1867],{"class":154,"line":177},[152,1861,1862],{"class":552},"  tool",[152,1864,556],{"class":447},[152,1866,553],{"class":180},[152,1868,676],{"class":447},[152,1870,1871,1874,1876,1878],{"class":154,"line":199},[152,1872,1873],{"class":552},"  arguments",[152,1875,556],{"class":447},[152,1877,984],{"class":180},[152,1879,676],{"class":447},[152,1881,1882],{"class":154,"line":206},[152,1883,1118],{"class":447},[70,1885,1886],{},"When something unexpected happens — and it will — you'll want to know exactly what the AI ran.",[80,1888,1890],{"id":1889},"go-connect-something","Go Connect Something",[70,1892,1893],{},"The fastest way to understand MCP is to set up one server and use it for a week. I'd start with whatever thing you context-switch to most often. For me that was error logs. For you it might be your database, or Stripe, or an internal API.",[70,1895,1896],{},"Pick that one thing. Get it working. The productivity shift is immediately obvious — and once you've felt the difference between \"paste this in\" and \"just ask,\" you'll start seeing connection points everywhere.",[70,1898,1899],{},"The infrastructure is there. The question is which wall you knock down first. 🎉",[1901,1902],"hr",{},[70,1904,1905],{},[90,1906,1907],{},"Resources:",[1560,1909,1910,1920,1928],{},[1563,1911,1912,1919],{},[1913,1914,1918],"a",{"href":1915,"rel":1916},"https://modelcontextprotocol.io",[1917],"nofollow","MCP Documentation"," — official spec and SDK docs",[1563,1921,1922,1927],{},[1913,1923,1926],{"href":1924,"rel":1925},"https://github.com/modelcontextprotocol/servers",[1917],"MCP Server Registry"," — community-maintained server list",[1563,1929,1930,1935],{},[1913,1931,1934],{"href":1932,"rel":1933},"https://docs.anthropic.com/en/docs/agents-and-tools/mcp",[1917],"Anthropic's MCP Quickstart"," — getting started with Claude Desktop",[1937,1938,1939],"style",{},"html pre.shiki code .sux-A, html code.shiki .sux-A{--shiki-default:#758575DD}html pre.shiki code .sNJcY, html code.shiki .sNJcY{--shiki-default:#C98A7D77}html pre.shiki code .s7rlk, html code.shiki .s7rlk{--shiki-default:#C98A7D}html pre.shiki code .s6RL2, html code.shiki .s6RL2{--shiki-default:#FDAEB7;--shiki-default-font-style:italic}html pre.shiki code .st-jp, html code.shiki .st-jp{--shiki-default:#BD976A}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);}html pre.shiki code .s3QIE, html code.shiki .s3QIE{--shiki-default:#4D9375}html pre.shiki code .s_pn2, html code.shiki .s_pn2{--shiki-default:#666666}html pre.shiki code .s_wWq, html code.shiki .s_wWq{--shiki-default:#CB7676}html pre.shiki code .sCK9x, html code.shiki .sCK9x{--shiki-default:#80A665}html pre.shiki code .sm68I, html code.shiki .sm68I{--shiki-default:#B8A965}html pre.shiki code .sxA9i, html code.shiki .sxA9i{--shiki-default:#4C9A91}html pre.shiki code .s6USN, html code.shiki .s6USN{--shiki-default:#B8A96577}",{"title":147,"searchDepth":162,"depth":162,"links":1941},[1942,1943,1949,1955,1956],{"id":82,"depth":162,"text":83},{"id":128,"depth":162,"text":129,"children":1944},[1945,1946,1947,1948],{"id":136,"depth":177,"text":137},{"id":242,"depth":177,"text":243},{"id":307,"depth":177,"text":308},{"id":378,"depth":177,"text":379},{"id":425,"depth":162,"text":426,"children":1950},[1951,1952,1953,1954],{"id":432,"depth":177,"text":433},{"id":1181,"depth":177,"text":1182},{"id":1398,"depth":177,"text":1399},{"id":1554,"depth":177,"text":1555},{"id":1718,"depth":162,"text":1719},{"id":1889,"depth":162,"text":1890},"2026-01-10T00:00:00.000Z","Discover how the Model Context Protocol lets AI interact with your databases, browsers, logs, and APIs directly. Learn what MCP is, explore production-ready servers, and build your own AI tools.","md","https://res.cloudinary.com/nbrett/image/upload/v1770325134/mcp_hero_image_ojda5z.svg",{},{"text":1963,"minutes":1964,"time":1965,"words":1966},"7 min read",6.545,392700,1309,{"title":34,"description":1958},null,"I6cfwCYQtYnQywIXvDtQS56aMg2YI9Qk3F6o_0UGaaE",[1971,1973],{"title":30,"path":31,"stem":32,"description":1972,"children":-1},"Discover how Go slices work and why they're one of the most versatile data structures in the language. Learn to create, manipulate, and optimize slices with practical examples and best practices.",{"title":38,"path":39,"stem":40,"description":1974,"children":-1},"Take your CSS Grid skills to the next level. Learn advanced techniques like grid-template-areas, auto-fit, minmax, and responsive patterns that make complex layouts simple and maintainable.",1774167726533]