[{"data":1,"prerenderedAt":2828},["ShallowReactive",2],{"blog-article-/blog/building-your-first-mcp-server-a-beginners-tutorial":3,"blog-surround-/blog/building-your-first-mcp-server-a-beginners-tutorial":2819},{"id":4,"title":5,"body":6,"canonical":2804,"date":2805,"description":2806,"extension":2807,"featured":846,"image":2808,"meta":2809,"navigation":846,"ogImage":2808,"path":2811,"provider":2808,"published":846,"seo":2812,"stem":2813,"tags":2814,"url":2808,"__hash__":2818},"blog/blog/building-your-first-mcp-server-a-beginners-tutorial.md","Building Your First MCP Server: A Beginners Tutorial",{"type":7,"value":8,"toc":2764},"minimark",[9,13,16,19,25,41,46,57,60,65,68,74,80,86,89,93,96,101,104,148,152,155,168,172,183,278,286,290,293,297,300,315,319,322,336,342,380,384,391,395,448,452,500,503,507,514,666,671,701,706,723,727,730,762,767,791,795,801,1023,1030,1034,1037,1041,1044,1070,1073,1088,1094,1098,1128,1134,1139,1147,1150,1154,1165,1169,1172,1186,1190,1193,1644,1648,1668,1671,1675,1678,1682,1728,1735,1834,1838,1864,1867,1873,1900,1906,1910,1913,1918,1926,1931,1939,1944,1952,1957,1965,1969,1975,2436,2440,2443,2447,2452,2480,2485,2512,2517,2544,2548,2556,2560,2565,2570,2584,2589,2615,2621,2624,2628,2633,2678,2683,2700,2705,2730,2740,2745,2752,2760],[10,11,12],"p",{},"Have you ever wanted your AI assistant to access real-time data? Model Context Protocol (MCP) servers make this possible, and they're surprisingly simple to build and use!",[10,14,15],{},"You may have already seen my videos and posts on using the Playwright MCP to go to a website and generate test ideas and then generate actual Playwright tests after first interacting with the site. Or how I used it to go shopping for me. This is the power of MCPs. It gives the AI agents tools to be able to do things such as connect to a browser or as in the GitHub MCP, create pull requests etc.",[10,17,18],{},"In this tutorial, you'll create a weather server that connects AI agents like GitHub Copilot to live weather data. We will use TypeScript for this demo but you can build MCP servers in other languages, links at the end of the post. By the end, you'll be able to ask your AI for weather information in any city and get real, up-to-date responses.",[10,20,21],{},[22,23,24],"strong",{},"What you'll learn:",[26,27,28,32,35,38],"ul",{},[29,30,31],"li",{},"How to build an MCP server from scratch using the TypeScript SDK",[29,33,34],{},"Connect it to a real weather API",[29,36,37],{},"Integrate it with VS Code and GitHub Copilot",[29,39,40],{},"Test and debug your server",[10,42,43],{},[22,44,45],{},"What you'll need:",[26,47,48,51,54],{},[29,49,50],{},"Basic TypeScript/JavaScript knowledge",[29,52,53],{},"Node.js installed on your machine",[29,55,56],{},"VS Code (optional, but recommended)",[10,58,59],{},"Let's get started!",[61,62,64],"h2",{"id":63},"what-is-an-mcp-server","What is an MCP Server?",[10,66,67],{},"Model Context Protocol (MCP) servers are bridges that connect AI agents to external tools and data sources. Think of them as translators that help AI understand and interact with real-world applications.",[10,69,70,73],{},[22,71,72],{},"The Problem:"," When you ask GitHub Copilot for weather information in VS Code, you'll get a response like this:",[75,76,77],"blockquote",{},[10,78,79],{},"\"I don't have access to real-time weather data or weather APIs through the available tools in this coding environment.\"",[10,81,82,85],{},[22,83,84],{},"The Solution:"," MCP servers provide the missing link, giving AI agents the tools they need to access live data and perform real actions.",[10,87,88],{},"Our weather server will act as a tool that any MCP-compatible AI can call to get current weather information for any city worldwide.",[61,90,92],{"id":91},"step-1-project-setup","Step 1: Project Setup",[10,94,95],{},"Let's create a new project and set up our development environment.",[97,98,100],"h3",{"id":99},"_1-initialize-the-project","1. Initialize the Project",[10,102,103],{},"Create a new directory and initialize it with npm:",[105,106,111],"pre",{"className":107,"code":108,"language":109,"meta":110,"style":110},"language-bash shiki shiki-themes github-light github-dark","mkdir mcp-weather-server\ncd mcp-weather-server\nnpm init -y\n","bash","",[112,113,114,127,136],"code",{"__ignoreMap":110},[115,116,119,123],"span",{"class":117,"line":118},"line",1,[115,120,122],{"class":121},"sScJk","mkdir",[115,124,126],{"class":125},"sZZnC"," mcp-weather-server\n",[115,128,130,134],{"class":117,"line":129},2,[115,131,133],{"class":132},"sj4cs","cd",[115,135,126],{"class":125},[115,137,139,142,145],{"class":117,"line":138},3,[115,140,141],{"class":121},"npm",[115,143,144],{"class":125}," init",[115,146,147],{"class":132}," -y\n",[97,149,151],{"id":150},"_2-create-the-main-file","2. Create the Main File",[10,153,154],{},"Create our main TypeScript file:",[105,156,158],{"className":107,"code":157,"language":109,"meta":110,"style":110},"touch main.ts\n",[112,159,160],{"__ignoreMap":110},[115,161,162,165],{"class":117,"line":118},[115,163,164],{"class":121},"touch",[115,166,167],{"class":125}," main.ts\n",[97,169,171],{"id":170},"_3-configure-packagejson","3. Configure Package.json",[10,173,174,175,178,179,182],{},"Open the project in VS Code (or your preferred editor) and modify ",[112,176,177],{},"package.json"," to enable ES modules by adding the ",[112,180,181],{},"type"," field:",[105,184,188],{"className":185,"code":186,"language":187,"meta":110,"style":110},"language-json shiki shiki-themes github-light github-dark","{\n  \"name\": \"mcp-weather-server\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  }\n}\n","json",[112,189,190,196,210,222,235,244,266,272],{"__ignoreMap":110},[115,191,192],{"class":117,"line":118},[115,193,195],{"class":194},"sVt8B","{\n",[115,197,198,201,204,207],{"class":117,"line":129},[115,199,200],{"class":132},"  \"name\"",[115,202,203],{"class":194},": ",[115,205,206],{"class":125},"\"mcp-weather-server\"",[115,208,209],{"class":194},",\n",[115,211,212,215,217,220],{"class":117,"line":138},[115,213,214],{"class":132},"  \"version\"",[115,216,203],{"class":194},[115,218,219],{"class":125},"\"1.0.0\"",[115,221,209],{"class":194},[115,223,225,228,230,233],{"class":117,"line":224},4,[115,226,227],{"class":132},"  \"type\"",[115,229,203],{"class":194},[115,231,232],{"class":125},"\"module\"",[115,234,209],{"class":194},[115,236,238,241],{"class":117,"line":237},5,[115,239,240],{"class":132},"  \"scripts\"",[115,242,243],{"class":194},": {\n",[115,245,247,250,252,255,258,261,263],{"class":117,"line":246},6,[115,248,249],{"class":132},"    \"test\"",[115,251,203],{"class":194},[115,253,254],{"class":125},"\"echo ",[115,256,257],{"class":132},"\\\"",[115,259,260],{"class":125},"Error: no test specified",[115,262,257],{"class":132},[115,264,265],{"class":125}," && exit 1\"\n",[115,267,269],{"class":117,"line":268},7,[115,270,271],{"class":194},"  }\n",[115,273,275],{"class":117,"line":274},8,[115,276,277],{"class":194},"}\n",[75,279,280],{},[10,281,282,285],{},[22,283,284],{},"Why ES modules?"," The MCP SDK uses modern JavaScript modules, so we need to enable them in our project.",[61,287,289],{"id":288},"step-2-install-dependencies","Step 2: Install Dependencies",[10,291,292],{},"Our MCP server needs two key libraries:",[97,294,296],{"id":295},"_1-install-the-mcp-sdk","1. Install the MCP SDK",[10,298,299],{},"The Model Context Protocol SDK provides everything needed to build MCP servers:",[105,301,303],{"className":107,"code":302,"language":109,"meta":110,"style":110},"npm install @modelcontextprotocol/sdk\n",[112,304,305],{"__ignoreMap":110},[115,306,307,309,312],{"class":117,"line":118},[115,308,141],{"class":121},[115,310,311],{"class":125}," install",[115,313,314],{"class":125}," @modelcontextprotocol/sdk\n",[97,316,318],{"id":317},"_2-install-zod-for-data-validation","2. Install Zod for Data Validation",[10,320,321],{},"Zod ensures our server receives valid data from AI agents:",[105,323,325],{"className":107,"code":324,"language":109,"meta":110,"style":110},"npm install zod\n",[112,326,327],{"__ignoreMap":110},[115,328,329,331,333],{"class":117,"line":118},[115,330,141],{"class":121},[115,332,311],{"class":125},[115,334,335],{"class":125}," zod\n",[10,337,338,339,341],{},"Your ",[112,340,177],{}," dependencies should now look like this:",[105,343,345],{"className":185,"code":344,"language":187,"meta":110,"style":110},"\"dependencies\": {\n  \"@modelcontextprotocol/sdk\": \"^1.13.1\",\n  \"zod\": \"^3.25.67\"\n}\n",[112,346,347,354,366,376],{"__ignoreMap":110},[115,348,349,352],{"class":117,"line":118},[115,350,351],{"class":125},"\"dependencies\"",[115,353,243],{"class":194},[115,355,356,359,361,364],{"class":117,"line":129},[115,357,358],{"class":132},"  \"@modelcontextprotocol/sdk\"",[115,360,203],{"class":194},[115,362,363],{"class":125},"\"^1.13.1\"",[115,365,209],{"class":194},[115,367,368,371,373],{"class":117,"line":138},[115,369,370],{"class":132},"  \"zod\"",[115,372,203],{"class":194},[115,374,375],{"class":125},"\"^3.25.67\"\n",[115,377,378],{"class":117,"line":224},[115,379,277],{"class":194},[61,381,383],{"id":382},"step-3-building-the-basic-server","Step 3: Building the Basic Server",[10,385,386,387,390],{},"Now let's create our MCP server. Open ",[112,388,389],{},"main.ts"," and let's build it step by step.",[97,392,394],{"id":393},"_1-add-the-required-imports","1. Add the Required Imports",[105,396,400],{"className":397,"code":398,"language":399,"meta":110,"style":110},"language-typescript shiki shiki-themes github-light github-dark","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from \"zod\";\n","typescript",[112,401,402,420,434],{"__ignoreMap":110},[115,403,404,408,411,414,417],{"class":117,"line":118},[115,405,407],{"class":406},"szBVR","import",[115,409,410],{"class":194}," { McpServer } ",[115,412,413],{"class":406},"from",[115,415,416],{"class":125}," \"@modelcontextprotocol/sdk/server/mcp.js\"",[115,418,419],{"class":194},";\n",[115,421,422,424,427,429,432],{"class":117,"line":129},[115,423,407],{"class":406},[115,425,426],{"class":194}," { StdioServerTransport } ",[115,428,413],{"class":406},[115,430,431],{"class":125}," '@modelcontextprotocol/sdk/server/stdio.js'",[115,433,419],{"class":194},[115,435,436,438,441,443,446],{"class":117,"line":138},[115,437,407],{"class":406},[115,439,440],{"class":194}," { z } ",[115,442,413],{"class":406},[115,444,445],{"class":125}," \"zod\"",[115,447,419],{"class":194},[97,449,451],{"id":450},"_2-create-the-server-instance","2. Create the Server Instance",[105,453,455],{"className":397,"code":454,"language":399,"meta":110,"style":110},"const server = new McpServer({\n  name: \"Weather Server\",\n  version: \"1.0.0\"\n});\n",[112,456,457,477,487,495],{"__ignoreMap":110},[115,458,459,462,465,468,471,474],{"class":117,"line":118},[115,460,461],{"class":406},"const",[115,463,464],{"class":132}," server",[115,466,467],{"class":406}," =",[115,469,470],{"class":406}," new",[115,472,473],{"class":121}," McpServer",[115,475,476],{"class":194},"({\n",[115,478,479,482,485],{"class":117,"line":129},[115,480,481],{"class":194},"  name: ",[115,483,484],{"class":125},"\"Weather Server\"",[115,486,209],{"class":194},[115,488,489,492],{"class":117,"line":138},[115,490,491],{"class":194},"  version: ",[115,493,494],{"class":125},"\"1.0.0\"\n",[115,496,497],{"class":117,"line":224},[115,498,499],{"class":194},"});\n",[10,501,502],{},"The server manages all communication using the MCP protocol between clients (like VS Code) and your tools.",[97,504,506],{"id":505},"_3-define-your-first-tool","3. Define Your First Tool",[10,508,509,510,513],{},"Tools are functions that AI agents can call. Let's create a ",[112,511,512],{},"get-weather"," tool:",[105,515,517],{"className":397,"code":516,"language":399,"meta":110,"style":110},"server.tool(\n  'get-weather',\n  'Tool to get the weather of a city',\n  {\n    city: z.string().describe(\"The name of the city to get the weather for\")\n  },\n  async ({ city }) => {\n    // For now, return a simple static response\n    return {\n      content: [{\n        type: \"text\",\n        text: `The weather in ${city} is sunny`\n      }]\n    };\n  }\n);\n",[112,518,519,530,537,544,549,572,577,598,604,612,618,629,643,649,655,660],{"__ignoreMap":110},[115,520,521,524,527],{"class":117,"line":118},[115,522,523],{"class":194},"server.",[115,525,526],{"class":121},"tool",[115,528,529],{"class":194},"(\n",[115,531,532,535],{"class":117,"line":129},[115,533,534],{"class":125},"  'get-weather'",[115,536,209],{"class":194},[115,538,539,542],{"class":117,"line":138},[115,540,541],{"class":125},"  'Tool to get the weather of a city'",[115,543,209],{"class":194},[115,545,546],{"class":117,"line":224},[115,547,548],{"class":194},"  {\n",[115,550,551,554,557,560,563,566,569],{"class":117,"line":237},[115,552,553],{"class":194},"    city: z.",[115,555,556],{"class":121},"string",[115,558,559],{"class":194},"().",[115,561,562],{"class":121},"describe",[115,564,565],{"class":194},"(",[115,567,568],{"class":125},"\"The name of the city to get the weather for\"",[115,570,571],{"class":194},")\n",[115,573,574],{"class":117,"line":246},[115,575,576],{"class":194},"  },\n",[115,578,579,582,585,589,592,595],{"class":117,"line":268},[115,580,581],{"class":406},"  async",[115,583,584],{"class":194}," ({ ",[115,586,588],{"class":587},"s4XuR","city",[115,590,591],{"class":194}," }) ",[115,593,594],{"class":406},"=>",[115,596,597],{"class":194}," {\n",[115,599,600],{"class":117,"line":274},[115,601,603],{"class":602},"sJ8bj","    // For now, return a simple static response\n",[115,605,607,610],{"class":117,"line":606},9,[115,608,609],{"class":406},"    return",[115,611,597],{"class":194},[115,613,615],{"class":117,"line":614},10,[115,616,617],{"class":194},"      content: [{\n",[115,619,621,624,627],{"class":117,"line":620},11,[115,622,623],{"class":194},"        type: ",[115,625,626],{"class":125},"\"text\"",[115,628,209],{"class":194},[115,630,632,635,638,640],{"class":117,"line":631},12,[115,633,634],{"class":194},"        text: ",[115,636,637],{"class":125},"`The weather in ${",[115,639,588],{"class":194},[115,641,642],{"class":125},"} is sunny`\n",[115,644,646],{"class":117,"line":645},13,[115,647,648],{"class":194},"      }]\n",[115,650,652],{"class":117,"line":651},14,[115,653,654],{"class":194},"    };\n",[115,656,658],{"class":117,"line":657},15,[115,659,271],{"class":194},[115,661,663],{"class":117,"line":662},16,[115,664,665],{"class":194},");\n",[10,667,668],{},[22,669,670],{},"Breaking down the tool definition:",[26,672,673,683,689,695],{},[29,674,675,678,679,682],{},[22,676,677],{},"Tool ID:"," ",[112,680,681],{},"'get-weather'"," - Unique identifier",[29,684,685,688],{},[22,686,687],{},"Description:"," Helps AI agents understand what this tool does",[29,690,691,694],{},[22,692,693],{},"Schema:"," Defines parameters (city must be a string)",[29,696,697,700],{},[22,698,699],{},"Function:"," The actual code that runs when called",[10,702,703],{},[22,704,705],{},"How it works:",[26,707,708,711,717,720],{},[29,709,710],{},"AI agent sees: \"Tool to get the weather of a city\"",[29,712,713,714],{},"AI agent calls it with: ",[112,715,716],{},"{ city: \"Paris\" }",[29,718,719],{},"Zod validates the input",[29,721,722],{},"Function returns: \"The weather in Paris is sunny\"",[97,724,726],{"id":725},"_4-set-up-communication","4. Set Up Communication",[10,728,729],{},"Finally, we need to set up how our server communicates with AI clients:",[105,731,733],{"className":397,"code":732,"language":399,"meta":110,"style":110},"const transport = new StdioServerTransport();\nserver.connect(transport);\n",[112,734,735,752],{"__ignoreMap":110},[115,736,737,739,742,744,746,749],{"class":117,"line":118},[115,738,461],{"class":406},[115,740,741],{"class":132}," transport",[115,743,467],{"class":406},[115,745,470],{"class":406},[115,747,748],{"class":121}," StdioServerTransport",[115,750,751],{"class":194},"();\n",[115,753,754,756,759],{"class":117,"line":129},[115,755,523],{"class":194},[115,757,758],{"class":121},"connect",[115,760,761],{"class":194},"(transport);\n",[10,763,764],{},[22,765,766],{},"What's happening here:",[26,768,769,775,778,788],{},[29,770,771,774],{},[112,772,773],{},"StdioServerTransport"," uses your terminal's input/output for communication",[29,776,777],{},"Perfect for local development",[29,779,780,781,784,785],{},"The server reads requests from ",[112,782,783],{},"stdin"," and writes responses to ",[112,786,787],{},"stdout",[29,789,790],{},"MCP protocol handles all the message formatting automatically",[97,792,794],{"id":793},"_5-complete-basic-server-example","5. Complete Basic Server Example",[10,796,797,798,800],{},"Your complete ",[112,799,389],{}," should now look like this:",[105,802,804],{"className":397,"code":803,"language":399,"meta":110,"style":110},"import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"Weather Server\",\n  version: \"1.0.0\"\n});\n\nserver.tool(\n  'get-weather',\n  'Tool to get the weather of a city',\n  {\n    city: z.string().describe(\"The name of the city to get the weather for\")\n  },\n  async ({ city }) => {\n    return {\n      content: [{\n        type: \"text\",\n        text: `The weather in ${city} is sunny`\n      }]\n    };\n  }\n);\n\nconst transport = new StdioServerTransport();\nserver.connect(transport);\n",[112,805,806,818,830,842,848,862,870,876,880,884,892,898,904,908,924,928,942,949,954,963,974,979,984,989,994,999,1014],{"__ignoreMap":110},[115,807,808,810,812,814,816],{"class":117,"line":118},[115,809,407],{"class":406},[115,811,410],{"class":194},[115,813,413],{"class":406},[115,815,416],{"class":125},[115,817,419],{"class":194},[115,819,820,822,824,826,828],{"class":117,"line":129},[115,821,407],{"class":406},[115,823,426],{"class":194},[115,825,413],{"class":406},[115,827,431],{"class":125},[115,829,419],{"class":194},[115,831,832,834,836,838,840],{"class":117,"line":138},[115,833,407],{"class":406},[115,835,440],{"class":194},[115,837,413],{"class":406},[115,839,445],{"class":125},[115,841,419],{"class":194},[115,843,844],{"class":117,"line":224},[115,845,847],{"emptyLinePlaceholder":846},true,"\n",[115,849,850,852,854,856,858,860],{"class":117,"line":237},[115,851,461],{"class":406},[115,853,464],{"class":132},[115,855,467],{"class":406},[115,857,470],{"class":406},[115,859,473],{"class":121},[115,861,476],{"class":194},[115,863,864,866,868],{"class":117,"line":246},[115,865,481],{"class":194},[115,867,484],{"class":125},[115,869,209],{"class":194},[115,871,872,874],{"class":117,"line":268},[115,873,491],{"class":194},[115,875,494],{"class":125},[115,877,878],{"class":117,"line":274},[115,879,499],{"class":194},[115,881,882],{"class":117,"line":606},[115,883,847],{"emptyLinePlaceholder":846},[115,885,886,888,890],{"class":117,"line":614},[115,887,523],{"class":194},[115,889,526],{"class":121},[115,891,529],{"class":194},[115,893,894,896],{"class":117,"line":620},[115,895,534],{"class":125},[115,897,209],{"class":194},[115,899,900,902],{"class":117,"line":631},[115,901,541],{"class":125},[115,903,209],{"class":194},[115,905,906],{"class":117,"line":645},[115,907,548],{"class":194},[115,909,910,912,914,916,918,920,922],{"class":117,"line":651},[115,911,553],{"class":194},[115,913,556],{"class":121},[115,915,559],{"class":194},[115,917,562],{"class":121},[115,919,565],{"class":194},[115,921,568],{"class":125},[115,923,571],{"class":194},[115,925,926],{"class":117,"line":657},[115,927,576],{"class":194},[115,929,930,932,934,936,938,940],{"class":117,"line":662},[115,931,581],{"class":406},[115,933,584],{"class":194},[115,935,588],{"class":587},[115,937,591],{"class":194},[115,939,594],{"class":406},[115,941,597],{"class":194},[115,943,945,947],{"class":117,"line":944},17,[115,946,609],{"class":406},[115,948,597],{"class":194},[115,950,952],{"class":117,"line":951},18,[115,953,617],{"class":194},[115,955,957,959,961],{"class":117,"line":956},19,[115,958,623],{"class":194},[115,960,626],{"class":125},[115,962,209],{"class":194},[115,964,966,968,970,972],{"class":117,"line":965},20,[115,967,634],{"class":194},[115,969,637],{"class":125},[115,971,588],{"class":194},[115,973,642],{"class":125},[115,975,977],{"class":117,"line":976},21,[115,978,648],{"class":194},[115,980,982],{"class":117,"line":981},22,[115,983,654],{"class":194},[115,985,987],{"class":117,"line":986},23,[115,988,271],{"class":194},[115,990,992],{"class":117,"line":991},24,[115,993,665],{"class":194},[115,995,997],{"class":117,"line":996},25,[115,998,847],{"emptyLinePlaceholder":846},[115,1000,1002,1004,1006,1008,1010,1012],{"class":117,"line":1001},26,[115,1003,461],{"class":406},[115,1005,741],{"class":132},[115,1007,467],{"class":406},[115,1009,470],{"class":406},[115,1011,748],{"class":121},[115,1013,751],{"class":194},[115,1015,1017,1019,1021],{"class":117,"line":1016},27,[115,1018,523],{"class":194},[115,1020,758],{"class":121},[115,1022,761],{"class":194},[10,1024,1025,1026,1029],{},"🎉 ",[22,1027,1028],{},"Congratulations!"," You've built your first MCP server. Let's test it!",[61,1031,1033],{"id":1032},"step-4-testing-with-mcp-inspector","Step 4: Testing with MCP Inspector",[10,1035,1036],{},"Before adding real weather data, let's test our server using the MCP Inspector, a web-based debugging tool for MCP servers.",[97,1038,1040],{"id":1039},"launch-the-inspector","Launch the Inspector",[10,1042,1043],{},"Run this command to open the MCP Inspector for your server:",[105,1045,1047],{"className":107,"code":1046,"language":109,"meta":110,"style":110},"npx -y @modelcontextprotocol/inspector npx -y tsx main.ts\n",[112,1048,1049],{"__ignoreMap":110},[115,1050,1051,1054,1057,1060,1063,1065,1068],{"class":117,"line":118},[115,1052,1053],{"class":121},"npx",[115,1055,1056],{"class":132}," -y",[115,1058,1059],{"class":125}," @modelcontextprotocol/inspector",[115,1061,1062],{"class":125}," npx",[115,1064,1056],{"class":132},[115,1066,1067],{"class":125}," tsx",[115,1069,167],{"class":125},[10,1071,1072],{},"After running the command, you'll see terminal output with:",[26,1074,1075,1082,1085],{},[29,1076,1077,1078,1081],{},"A localhost URL (like ",[112,1079,1080],{},"http://127.0.0.1:6274",")",[29,1083,1084],{},"A unique session token",[29,1086,1087],{},"A direct link with the token pre-filled",[10,1089,1090,1093],{},[22,1091,1092],{},"💡 Tip:"," Click the link with the token already included to avoid manual entry.",[97,1095,1097],{"id":1096},"connect-and-test","Connect and Test",[1099,1100,1101,1107,1113,1122],"ol",{},[29,1102,1103,1106],{},[22,1104,1105],{},"Connect:"," Click the \"Connect\" button in the Inspector",[29,1108,1109,1112],{},[22,1110,1111],{},"Navigate:"," Click \"Tools\" in the top navigation",[29,1114,1115,1118,1119,1121],{},[22,1116,1117],{},"Select:"," Choose your ",[112,1120,512],{}," tool",[29,1123,1124,1127],{},[22,1125,1126],{},"Test:"," Enter a city name (like \"Palma de Mallorca\") and click \"Run Tool\"",[10,1129,1130,1131],{},"You should see the response: ",[112,1132,1133],{},"\"The weather in Palma de Mallorca is sunny\"",[10,1135,1136],{},[22,1137,1138],{},"Troubleshooting:",[26,1140,1141],{},[29,1142,1143,1146],{},[22,1144,1145],{},"Connection Error?"," Make sure you used the link with the pre-filled token",[10,1148,1149],{},"Perfect! Your MCP server is working. Now let's make it actually useful.",[61,1151,1153],{"id":1152},"step-5-adding-real-weather-data","Step 5: Adding Real Weather Data",[10,1155,1156,1157,1164],{},"Time to make our server actually useful! We'll integrate with ",[1158,1159,1163],"a",{"href":1160,"rel":1161},"https://open-meteo.com/",[1162],"nofollow","Open-Meteo",", a free weather API that requires no API key.",[97,1166,1168],{"id":1167},"how-the-weather-api-works","How the Weather API Works",[10,1170,1171],{},"To get weather data, we need a two-step process:",[1099,1173,1174,1180],{},[29,1175,1176,1179],{},[22,1177,1178],{},"Convert city name → coordinates"," (using the Geocoding API)",[29,1181,1182,1185],{},[22,1183,1184],{},"Get weather using coordinates"," (using the Weather API)",[97,1187,1189],{"id":1188},"update-your-tool-function","Update Your Tool Function",[10,1191,1192],{},"Replace your existing tool function with this enhanced version:",[105,1194,1196],{"className":397,"code":1195,"language":399,"meta":110,"style":110},"server.tool(\n  'get-weather',\n  'Tool to get the weather of a city',\n  {\n    city: z.string().describe(\"The name of the city to get the weather for\")\n  },\n  async ({ city }) => {\n    try {\n      // Step 1: Get coordinates for the city\n      const geoResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${city}&count=1&language=en&format=json`);\n      const geoData = await geoResponse.json();\n\n      // Handle city not found\n      if (!geoData.results || geoData.results.length === 0) {\n        return {\n          content: [{\n            type: \"text\",\n            text: `Sorry, I couldn't find a city named \"${city}\". Please check the spelling and try again.`\n          }]\n        };\n      }\n\n      // Step 2: Get weather data using coordinates\n      const { latitude, longitude } = geoData.results[0];\n      const weatherResponse = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code&hourly=temperature_2m,precipitation&forecast_days=1`);\n      const weatherData = await weatherResponse.json();\n\n      // Return the complete weather data as JSON\n      return {\n        content: [{\n          type: \"text\",\n          text: JSON.stringify(weatherData, null, 2)\n        }]\n      };\n    } catch (error) {\n      return {\n        content: [{\n          type: \"text\",\n          text: `Error fetching weather data: ${error.message}`\n        }]\n      };\n    }\n  }\n);\n",[112,1197,1198,1206,1212,1218,1222,1238,1242,1256,1263,1268,1296,1314,1318,1323,1355,1362,1367,1376,1389,1394,1399,1404,1408,1413,1444,1474,1492,1496,1502,1510,1516,1526,1554,1560,1566,1578,1585,1590,1599,1618,1623,1628,1634,1639],{"__ignoreMap":110},[115,1199,1200,1202,1204],{"class":117,"line":118},[115,1201,523],{"class":194},[115,1203,526],{"class":121},[115,1205,529],{"class":194},[115,1207,1208,1210],{"class":117,"line":129},[115,1209,534],{"class":125},[115,1211,209],{"class":194},[115,1213,1214,1216],{"class":117,"line":138},[115,1215,541],{"class":125},[115,1217,209],{"class":194},[115,1219,1220],{"class":117,"line":224},[115,1221,548],{"class":194},[115,1223,1224,1226,1228,1230,1232,1234,1236],{"class":117,"line":237},[115,1225,553],{"class":194},[115,1227,556],{"class":121},[115,1229,559],{"class":194},[115,1231,562],{"class":121},[115,1233,565],{"class":194},[115,1235,568],{"class":125},[115,1237,571],{"class":194},[115,1239,1240],{"class":117,"line":246},[115,1241,576],{"class":194},[115,1243,1244,1246,1248,1250,1252,1254],{"class":117,"line":268},[115,1245,581],{"class":406},[115,1247,584],{"class":194},[115,1249,588],{"class":587},[115,1251,591],{"class":194},[115,1253,594],{"class":406},[115,1255,597],{"class":194},[115,1257,1258,1261],{"class":117,"line":274},[115,1259,1260],{"class":406},"    try",[115,1262,597],{"class":194},[115,1264,1265],{"class":117,"line":606},[115,1266,1267],{"class":602},"      // Step 1: Get coordinates for the city\n",[115,1269,1270,1273,1276,1278,1281,1284,1286,1289,1291,1294],{"class":117,"line":614},[115,1271,1272],{"class":406},"      const",[115,1274,1275],{"class":132}," geoResponse",[115,1277,467],{"class":406},[115,1279,1280],{"class":406}," await",[115,1282,1283],{"class":121}," fetch",[115,1285,565],{"class":194},[115,1287,1288],{"class":125},"`https://geocoding-api.open-meteo.com/v1/search?name=${",[115,1290,588],{"class":194},[115,1292,1293],{"class":125},"}&count=1&language=en&format=json`",[115,1295,665],{"class":194},[115,1297,1298,1300,1303,1305,1307,1310,1312],{"class":117,"line":620},[115,1299,1272],{"class":406},[115,1301,1302],{"class":132}," geoData",[115,1304,467],{"class":406},[115,1306,1280],{"class":406},[115,1308,1309],{"class":194}," geoResponse.",[115,1311,187],{"class":121},[115,1313,751],{"class":194},[115,1315,1316],{"class":117,"line":631},[115,1317,847],{"emptyLinePlaceholder":846},[115,1319,1320],{"class":117,"line":645},[115,1321,1322],{"class":602},"      // Handle city not found\n",[115,1324,1325,1328,1331,1334,1337,1340,1343,1346,1349,1352],{"class":117,"line":651},[115,1326,1327],{"class":406},"      if",[115,1329,1330],{"class":194}," (",[115,1332,1333],{"class":406},"!",[115,1335,1336],{"class":194},"geoData.results ",[115,1338,1339],{"class":406},"||",[115,1341,1342],{"class":194}," geoData.results.",[115,1344,1345],{"class":132},"length",[115,1347,1348],{"class":406}," ===",[115,1350,1351],{"class":132}," 0",[115,1353,1354],{"class":194},") {\n",[115,1356,1357,1360],{"class":117,"line":657},[115,1358,1359],{"class":406},"        return",[115,1361,597],{"class":194},[115,1363,1364],{"class":117,"line":662},[115,1365,1366],{"class":194},"          content: [{\n",[115,1368,1369,1372,1374],{"class":117,"line":944},[115,1370,1371],{"class":194},"            type: ",[115,1373,626],{"class":125},[115,1375,209],{"class":194},[115,1377,1378,1381,1384,1386],{"class":117,"line":951},[115,1379,1380],{"class":194},"            text: ",[115,1382,1383],{"class":125},"`Sorry, I couldn't find a city named \"${",[115,1385,588],{"class":194},[115,1387,1388],{"class":125},"}\". Please check the spelling and try again.`\n",[115,1390,1391],{"class":117,"line":956},[115,1392,1393],{"class":194},"          }]\n",[115,1395,1396],{"class":117,"line":965},[115,1397,1398],{"class":194},"        };\n",[115,1400,1401],{"class":117,"line":976},[115,1402,1403],{"class":194},"      }\n",[115,1405,1406],{"class":117,"line":981},[115,1407,847],{"emptyLinePlaceholder":846},[115,1409,1410],{"class":117,"line":986},[115,1411,1412],{"class":602},"      // Step 2: Get weather data using coordinates\n",[115,1414,1415,1417,1420,1423,1426,1429,1432,1435,1438,1441],{"class":117,"line":991},[115,1416,1272],{"class":406},[115,1418,1419],{"class":194}," { ",[115,1421,1422],{"class":132},"latitude",[115,1424,1425],{"class":194},", ",[115,1427,1428],{"class":132},"longitude",[115,1430,1431],{"class":194}," } ",[115,1433,1434],{"class":406},"=",[115,1436,1437],{"class":194}," geoData.results[",[115,1439,1440],{"class":132},"0",[115,1442,1443],{"class":194},"];\n",[115,1445,1446,1448,1451,1453,1455,1457,1459,1462,1464,1467,1469,1472],{"class":117,"line":996},[115,1447,1272],{"class":406},[115,1449,1450],{"class":132}," weatherResponse",[115,1452,467],{"class":406},[115,1454,1280],{"class":406},[115,1456,1283],{"class":121},[115,1458,565],{"class":194},[115,1460,1461],{"class":125},"`https://api.open-meteo.com/v1/forecast?latitude=${",[115,1463,1422],{"class":194},[115,1465,1466],{"class":125},"}&longitude=${",[115,1468,1428],{"class":194},[115,1470,1471],{"class":125},"}&current=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code&hourly=temperature_2m,precipitation&forecast_days=1`",[115,1473,665],{"class":194},[115,1475,1476,1478,1481,1483,1485,1488,1490],{"class":117,"line":1001},[115,1477,1272],{"class":406},[115,1479,1480],{"class":132}," weatherData",[115,1482,467],{"class":406},[115,1484,1280],{"class":406},[115,1486,1487],{"class":194}," weatherResponse.",[115,1489,187],{"class":121},[115,1491,751],{"class":194},[115,1493,1494],{"class":117,"line":1016},[115,1495,847],{"emptyLinePlaceholder":846},[115,1497,1499],{"class":117,"line":1498},28,[115,1500,1501],{"class":602},"      // Return the complete weather data as JSON\n",[115,1503,1505,1508],{"class":117,"line":1504},29,[115,1506,1507],{"class":406},"      return",[115,1509,597],{"class":194},[115,1511,1513],{"class":117,"line":1512},30,[115,1514,1515],{"class":194},"        content: [{\n",[115,1517,1519,1522,1524],{"class":117,"line":1518},31,[115,1520,1521],{"class":194},"          type: ",[115,1523,626],{"class":125},[115,1525,209],{"class":194},[115,1527,1529,1532,1535,1538,1541,1544,1547,1549,1552],{"class":117,"line":1528},32,[115,1530,1531],{"class":194},"          text: ",[115,1533,1534],{"class":132},"JSON",[115,1536,1537],{"class":194},".",[115,1539,1540],{"class":121},"stringify",[115,1542,1543],{"class":194},"(weatherData, ",[115,1545,1546],{"class":132},"null",[115,1548,1425],{"class":194},[115,1550,1551],{"class":132},"2",[115,1553,571],{"class":194},[115,1555,1557],{"class":117,"line":1556},33,[115,1558,1559],{"class":194},"        }]\n",[115,1561,1563],{"class":117,"line":1562},34,[115,1564,1565],{"class":194},"      };\n",[115,1567,1569,1572,1575],{"class":117,"line":1568},35,[115,1570,1571],{"class":194},"    } ",[115,1573,1574],{"class":406},"catch",[115,1576,1577],{"class":194}," (error) {\n",[115,1579,1581,1583],{"class":117,"line":1580},36,[115,1582,1507],{"class":406},[115,1584,597],{"class":194},[115,1586,1588],{"class":117,"line":1587},37,[115,1589,1515],{"class":194},[115,1591,1593,1595,1597],{"class":117,"line":1592},38,[115,1594,1521],{"class":194},[115,1596,626],{"class":125},[115,1598,209],{"class":194},[115,1600,1602,1604,1607,1610,1612,1615],{"class":117,"line":1601},39,[115,1603,1531],{"class":194},[115,1605,1606],{"class":125},"`Error fetching weather data: ${",[115,1608,1609],{"class":194},"error",[115,1611,1537],{"class":125},[115,1613,1614],{"class":194},"message",[115,1616,1617],{"class":125},"}`\n",[115,1619,1621],{"class":117,"line":1620},40,[115,1622,1559],{"class":194},[115,1624,1626],{"class":117,"line":1625},41,[115,1627,1565],{"class":194},[115,1629,1631],{"class":117,"line":1630},42,[115,1632,1633],{"class":194},"    }\n",[115,1635,1637],{"class":117,"line":1636},43,[115,1638,271],{"class":194},[115,1640,1642],{"class":117,"line":1641},44,[115,1643,665],{"class":194},[97,1645,1647],{"id":1646},"test-the-real-data","Test the Real Data",[1099,1649,1650,1656,1662],{},[29,1651,1652,1655],{},[22,1653,1654],{},"Restart"," your MCP Inspector (Ctrl+C, then re-run the command)",[29,1657,1658,1661],{},[22,1659,1660],{},"Reconnect"," in the web interface",[29,1663,1664,1667],{},[22,1665,1666],{},"Test"," with a real city like \"Tokyo\" or \"New York\"",[10,1669,1670],{},"You should now see actual weather data instead of \"sunny\"! 🌤️",[61,1672,1674],{"id":1673},"step-6-integration-with-vs-code-and-github-copilot","Step 6: Integration with VS Code and GitHub Copilot",[10,1676,1677],{},"Now let's connect your weather server to VS Code so you can use it with GitHub Copilot!",[97,1679,1681],{"id":1680},"register-the-server","Register the Server",[1099,1683,1684,1692,1700,1706,1714,1722],{},[29,1685,1686,678,1689],{},[22,1687,1688],{},"Open Command Palette:",[112,1690,1691],{},"Cmd/Ctrl + Shift + P",[29,1693,1694,678,1697],{},[22,1695,1696],{},"Type:",[112,1698,1699],{},"MCP: Add Server",[29,1701,1702,1705],{},[22,1703,1704],{},"Choose:"," \"Local server using stdio\"",[29,1707,1708,678,1711],{},[22,1709,1710],{},"Enter Command:",[112,1712,1713],{},"npx -y tsx main.ts",[29,1715,1716,678,1719],{},[22,1717,1718],{},"Name:",[112,1720,1721],{},"my-weather-server",[29,1723,1724,1727],{},[22,1725,1726],{},"Setup Type:"," Local setup",[10,1729,1730,1731,1734],{},"This creates a ",[112,1732,1733],{},".vscode/mcp.json"," file in your project:",[105,1736,1738],{"className":185,"code":1737,"language":187,"meta":110,"style":110},"{\n  \"inputs\": [],\n  \"servers\": {\n    \"my-weather-server\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"tsx\",\n        \"/Users/your-username/path/to/main.ts\"\n      ]\n    }\n  }\n}\n",[112,1739,1740,1744,1752,1759,1766,1778,1790,1798,1805,1812,1817,1822,1826,1830],{"__ignoreMap":110},[115,1741,1742],{"class":117,"line":118},[115,1743,195],{"class":194},[115,1745,1746,1749],{"class":117,"line":129},[115,1747,1748],{"class":132},"  \"inputs\"",[115,1750,1751],{"class":194},": [],\n",[115,1753,1754,1757],{"class":117,"line":138},[115,1755,1756],{"class":132},"  \"servers\"",[115,1758,243],{"class":194},[115,1760,1761,1764],{"class":117,"line":224},[115,1762,1763],{"class":132},"    \"my-weather-server\"",[115,1765,243],{"class":194},[115,1767,1768,1771,1773,1776],{"class":117,"line":237},[115,1769,1770],{"class":132},"      \"type\"",[115,1772,203],{"class":194},[115,1774,1775],{"class":125},"\"stdio\"",[115,1777,209],{"class":194},[115,1779,1780,1783,1785,1788],{"class":117,"line":246},[115,1781,1782],{"class":132},"      \"command\"",[115,1784,203],{"class":194},[115,1786,1787],{"class":125},"\"npx\"",[115,1789,209],{"class":194},[115,1791,1792,1795],{"class":117,"line":268},[115,1793,1794],{"class":132},"      \"args\"",[115,1796,1797],{"class":194},": [\n",[115,1799,1800,1803],{"class":117,"line":274},[115,1801,1802],{"class":125},"        \"-y\"",[115,1804,209],{"class":194},[115,1806,1807,1810],{"class":117,"line":606},[115,1808,1809],{"class":125},"        \"tsx\"",[115,1811,209],{"class":194},[115,1813,1814],{"class":117,"line":614},[115,1815,1816],{"class":125},"        \"/Users/your-username/path/to/main.ts\"\n",[115,1818,1819],{"class":117,"line":620},[115,1820,1821],{"class":194},"      ]\n",[115,1823,1824],{"class":117,"line":631},[115,1825,1633],{"class":194},[115,1827,1828],{"class":117,"line":645},[115,1829,271],{"class":194},[115,1831,1832],{"class":117,"line":651},[115,1833,277],{"class":194},[97,1835,1837],{"id":1836},"start-and-test","Start and Test",[1099,1839,1840,1846,1852,1858],{},[29,1841,1842,1845],{},[22,1843,1844],{},"Start the server:"," Click the \"Start\" button next to your server name in the MCP panel",[29,1847,1848,1851],{},[22,1849,1850],{},"Verify:"," You should see \"Running\" status",[29,1853,1854,1857],{},[22,1855,1856],{},"Switch to Agent Mode:"," Click the Copilot sidebar → \"Agent Mode\"",[29,1859,1860,1863],{},[22,1861,1862],{},"Ask:"," \"What's the weather like in Tokyo?\"",[10,1865,1866],{},"GitHub Copilot will ask permission to use your weather tool, click \"Continue\" to proceed.",[10,1868,1869,1872],{},[22,1870,1871],{},"Expected Result:"," Instead of raw JSON, you'll get a beautifully formatted weather report like this:",[105,1874,1878],{"className":1875,"code":1876,"language":1877,"meta":110,"style":110},"language-markdown shiki shiki-themes github-light github-dark","> **Weather in Tokyo Today**\n> **Temperature:** 28°C (feels like 32°C)\n> **Humidity:** 75%\n> **Conditions:** Partly cloudy with light rain expected in the evening\n","markdown",[112,1879,1880,1885,1890,1895],{"__ignoreMap":110},[115,1881,1882],{"class":117,"line":118},[115,1883,1884],{},"> **Weather in Tokyo Today**\n",[115,1886,1887],{"class":117,"line":129},[115,1888,1889],{},"> **Temperature:** 28°C (feels like 32°C)\n",[115,1891,1892],{"class":117,"line":138},[115,1893,1894],{},"> **Humidity:** 75%\n",[115,1896,1897],{"class":117,"line":224},[115,1898,1899],{},"> **Conditions:** Partly cloudy with light rain expected in the evening\n",[10,1901,1902,1905],{},[22,1903,1904],{},"Perfect!"," The AI transforms your raw weather data into a beautiful, human-readable format automatically.",[61,1907,1909],{"id":1908},"why-this-is-powerful","Why This is Powerful",[10,1911,1912],{},"Your weather server demonstrates the true power of MCP:",[10,1914,1915],{},[22,1916,1917],{},"🤖 AI Does the Heavy Lifting",[26,1919,1920,1923],{},[29,1921,1922],{},"You provide raw data, AI creates beautiful presentations",[29,1924,1925],{},"No need to format responses, the AI handles user experience",[10,1927,1928],{},[22,1929,1930],{},"🔗 Universal Compatibility",[26,1932,1933,1936],{},[29,1934,1935],{},"Works with any MCP-compatible tool (VS Code, Claude, etc.)",[29,1937,1938],{},"Write once, use everywhere",[10,1940,1941],{},[22,1942,1943],{},"⚡ Real-time Integration",[26,1945,1946,1949],{},[29,1947,1948],{},"Always current data, no caching issues",[29,1950,1951],{},"Works seamlessly within your development environment",[10,1953,1954],{},[22,1955,1956],{},"📈 Easy to Extend",[26,1958,1959,1962],{},[29,1960,1961],{},"Add weather alerts, forecasts, or air quality data",[29,1963,1964],{},"Build additional tools in the same server",[61,1966,1968],{"id":1967},"complete-code-reference","Complete Code Reference",[10,1970,1971,1972,1974],{},"Here's your final ",[112,1973,389],{}," file:",[105,1976,1978],{"className":397,"code":1977,"language":399,"meta":110,"style":110},"import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"Weather Server\",\n  version: \"1.0.0\"\n});\n\nserver.tool(\n  'get-weather',\n  'Tool to get the weather of a city',\n  {\n    city: z.string().describe(\"The name of the city to get the weather for\")\n  },\n  async ({ city }) => {\n    try {\n      const response = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${city}&count=10&language=en&format=json`);\n      const data = await response.json();\n\n      if (data.results.length === 0) {\n        return {\n          content: [{\n            type: \"text\",\n            text: `No results found for city: ${city}`\n          }]\n        };\n      }\n\n      const { latitude, longitude } = data.results[0];\n      const weatherResponse = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&hourly=temperature_2m,precipitation,apparent_temperature,relative_humidity_2m&forecast_days=1`);\n      const weatherData = await weatherResponse.json();\n\n      return {\n        content: [{\n          type: \"text\",\n          text: JSON.stringify(weatherData, null, 2)\n        }]\n      };\n    } catch (error) {\n      return {\n        content: [{\n          type: \"text\",\n          text: `Error fetching weather data: ${error.message}`\n        }]\n      };\n    }\n  }\n);\n\nconst transport = new StdioServerTransport();\nserver.connect(transport);\n",[112,1979,1980,1992,2004,2016,2020,2034,2042,2048,2052,2056,2064,2070,2076,2080,2096,2100,2114,2120,2144,2162,2166,2181,2187,2191,2199,2210,2214,2218,2222,2226,2249,2276,2292,2296,2302,2306,2314,2334,2338,2342,2350,2356,2360,2368,2382,2387,2392,2397,2402,2407,2412,2427],{"__ignoreMap":110},[115,1981,1982,1984,1986,1988,1990],{"class":117,"line":118},[115,1983,407],{"class":406},[115,1985,410],{"class":194},[115,1987,413],{"class":406},[115,1989,416],{"class":125},[115,1991,419],{"class":194},[115,1993,1994,1996,1998,2000,2002],{"class":117,"line":129},[115,1995,407],{"class":406},[115,1997,426],{"class":194},[115,1999,413],{"class":406},[115,2001,431],{"class":125},[115,2003,419],{"class":194},[115,2005,2006,2008,2010,2012,2014],{"class":117,"line":138},[115,2007,407],{"class":406},[115,2009,440],{"class":194},[115,2011,413],{"class":406},[115,2013,445],{"class":125},[115,2015,419],{"class":194},[115,2017,2018],{"class":117,"line":224},[115,2019,847],{"emptyLinePlaceholder":846},[115,2021,2022,2024,2026,2028,2030,2032],{"class":117,"line":237},[115,2023,461],{"class":406},[115,2025,464],{"class":132},[115,2027,467],{"class":406},[115,2029,470],{"class":406},[115,2031,473],{"class":121},[115,2033,476],{"class":194},[115,2035,2036,2038,2040],{"class":117,"line":246},[115,2037,481],{"class":194},[115,2039,484],{"class":125},[115,2041,209],{"class":194},[115,2043,2044,2046],{"class":117,"line":268},[115,2045,491],{"class":194},[115,2047,494],{"class":125},[115,2049,2050],{"class":117,"line":274},[115,2051,499],{"class":194},[115,2053,2054],{"class":117,"line":606},[115,2055,847],{"emptyLinePlaceholder":846},[115,2057,2058,2060,2062],{"class":117,"line":614},[115,2059,523],{"class":194},[115,2061,526],{"class":121},[115,2063,529],{"class":194},[115,2065,2066,2068],{"class":117,"line":620},[115,2067,534],{"class":125},[115,2069,209],{"class":194},[115,2071,2072,2074],{"class":117,"line":631},[115,2073,541],{"class":125},[115,2075,209],{"class":194},[115,2077,2078],{"class":117,"line":645},[115,2079,548],{"class":194},[115,2081,2082,2084,2086,2088,2090,2092,2094],{"class":117,"line":651},[115,2083,553],{"class":194},[115,2085,556],{"class":121},[115,2087,559],{"class":194},[115,2089,562],{"class":121},[115,2091,565],{"class":194},[115,2093,568],{"class":125},[115,2095,571],{"class":194},[115,2097,2098],{"class":117,"line":657},[115,2099,576],{"class":194},[115,2101,2102,2104,2106,2108,2110,2112],{"class":117,"line":662},[115,2103,581],{"class":406},[115,2105,584],{"class":194},[115,2107,588],{"class":587},[115,2109,591],{"class":194},[115,2111,594],{"class":406},[115,2113,597],{"class":194},[115,2115,2116,2118],{"class":117,"line":944},[115,2117,1260],{"class":406},[115,2119,597],{"class":194},[115,2121,2122,2124,2127,2129,2131,2133,2135,2137,2139,2142],{"class":117,"line":951},[115,2123,1272],{"class":406},[115,2125,2126],{"class":132}," response",[115,2128,467],{"class":406},[115,2130,1280],{"class":406},[115,2132,1283],{"class":121},[115,2134,565],{"class":194},[115,2136,1288],{"class":125},[115,2138,588],{"class":194},[115,2140,2141],{"class":125},"}&count=10&language=en&format=json`",[115,2143,665],{"class":194},[115,2145,2146,2148,2151,2153,2155,2158,2160],{"class":117,"line":956},[115,2147,1272],{"class":406},[115,2149,2150],{"class":132}," data",[115,2152,467],{"class":406},[115,2154,1280],{"class":406},[115,2156,2157],{"class":194}," response.",[115,2159,187],{"class":121},[115,2161,751],{"class":194},[115,2163,2164],{"class":117,"line":965},[115,2165,847],{"emptyLinePlaceholder":846},[115,2167,2168,2170,2173,2175,2177,2179],{"class":117,"line":976},[115,2169,1327],{"class":406},[115,2171,2172],{"class":194}," (data.results.",[115,2174,1345],{"class":132},[115,2176,1348],{"class":406},[115,2178,1351],{"class":132},[115,2180,1354],{"class":194},[115,2182,2183,2185],{"class":117,"line":981},[115,2184,1359],{"class":406},[115,2186,597],{"class":194},[115,2188,2189],{"class":117,"line":986},[115,2190,1366],{"class":194},[115,2192,2193,2195,2197],{"class":117,"line":991},[115,2194,1371],{"class":194},[115,2196,626],{"class":125},[115,2198,209],{"class":194},[115,2200,2201,2203,2206,2208],{"class":117,"line":996},[115,2202,1380],{"class":194},[115,2204,2205],{"class":125},"`No results found for city: ${",[115,2207,588],{"class":194},[115,2209,1617],{"class":125},[115,2211,2212],{"class":117,"line":1001},[115,2213,1393],{"class":194},[115,2215,2216],{"class":117,"line":1016},[115,2217,1398],{"class":194},[115,2219,2220],{"class":117,"line":1498},[115,2221,1403],{"class":194},[115,2223,2224],{"class":117,"line":1504},[115,2225,847],{"emptyLinePlaceholder":846},[115,2227,2228,2230,2232,2234,2236,2238,2240,2242,2245,2247],{"class":117,"line":1512},[115,2229,1272],{"class":406},[115,2231,1419],{"class":194},[115,2233,1422],{"class":132},[115,2235,1425],{"class":194},[115,2237,1428],{"class":132},[115,2239,1431],{"class":194},[115,2241,1434],{"class":406},[115,2243,2244],{"class":194}," data.results[",[115,2246,1440],{"class":132},[115,2248,1443],{"class":194},[115,2250,2251,2253,2255,2257,2259,2261,2263,2265,2267,2269,2271,2274],{"class":117,"line":1518},[115,2252,1272],{"class":406},[115,2254,1450],{"class":132},[115,2256,467],{"class":406},[115,2258,1280],{"class":406},[115,2260,1283],{"class":121},[115,2262,565],{"class":194},[115,2264,1461],{"class":125},[115,2266,1422],{"class":194},[115,2268,1466],{"class":125},[115,2270,1428],{"class":194},[115,2272,2273],{"class":125},"}&hourly=temperature_2m,precipitation,apparent_temperature,relative_humidity_2m&forecast_days=1`",[115,2275,665],{"class":194},[115,2277,2278,2280,2282,2284,2286,2288,2290],{"class":117,"line":1528},[115,2279,1272],{"class":406},[115,2281,1480],{"class":132},[115,2283,467],{"class":406},[115,2285,1280],{"class":406},[115,2287,1487],{"class":194},[115,2289,187],{"class":121},[115,2291,751],{"class":194},[115,2293,2294],{"class":117,"line":1556},[115,2295,847],{"emptyLinePlaceholder":846},[115,2297,2298,2300],{"class":117,"line":1562},[115,2299,1507],{"class":406},[115,2301,597],{"class":194},[115,2303,2304],{"class":117,"line":1568},[115,2305,1515],{"class":194},[115,2307,2308,2310,2312],{"class":117,"line":1580},[115,2309,1521],{"class":194},[115,2311,626],{"class":125},[115,2313,209],{"class":194},[115,2315,2316,2318,2320,2322,2324,2326,2328,2330,2332],{"class":117,"line":1587},[115,2317,1531],{"class":194},[115,2319,1534],{"class":132},[115,2321,1537],{"class":194},[115,2323,1540],{"class":121},[115,2325,1543],{"class":194},[115,2327,1546],{"class":132},[115,2329,1425],{"class":194},[115,2331,1551],{"class":132},[115,2333,571],{"class":194},[115,2335,2336],{"class":117,"line":1592},[115,2337,1559],{"class":194},[115,2339,2340],{"class":117,"line":1601},[115,2341,1565],{"class":194},[115,2343,2344,2346,2348],{"class":117,"line":1620},[115,2345,1571],{"class":194},[115,2347,1574],{"class":406},[115,2349,1577],{"class":194},[115,2351,2352,2354],{"class":117,"line":1625},[115,2353,1507],{"class":406},[115,2355,597],{"class":194},[115,2357,2358],{"class":117,"line":1630},[115,2359,1515],{"class":194},[115,2361,2362,2364,2366],{"class":117,"line":1636},[115,2363,1521],{"class":194},[115,2365,626],{"class":125},[115,2367,209],{"class":194},[115,2369,2370,2372,2374,2376,2378,2380],{"class":117,"line":1641},[115,2371,1531],{"class":194},[115,2373,1606],{"class":125},[115,2375,1609],{"class":194},[115,2377,1537],{"class":125},[115,2379,1614],{"class":194},[115,2381,1617],{"class":125},[115,2383,2385],{"class":117,"line":2384},45,[115,2386,1559],{"class":194},[115,2388,2390],{"class":117,"line":2389},46,[115,2391,1565],{"class":194},[115,2393,2395],{"class":117,"line":2394},47,[115,2396,1633],{"class":194},[115,2398,2400],{"class":117,"line":2399},48,[115,2401,271],{"class":194},[115,2403,2405],{"class":117,"line":2404},49,[115,2406,665],{"class":194},[115,2408,2410],{"class":117,"line":2409},50,[115,2411,847],{"emptyLinePlaceholder":846},[115,2413,2415,2417,2419,2421,2423,2425],{"class":117,"line":2414},51,[115,2416,461],{"class":406},[115,2418,741],{"class":132},[115,2420,467],{"class":406},[115,2422,470],{"class":406},[115,2424,748],{"class":121},[115,2426,751],{"class":194},[115,2428,2430,2432,2434],{"class":117,"line":2429},52,[115,2431,523],{"class":194},[115,2433,758],{"class":121},[115,2435,761],{"class":194},[61,2437,2439],{"id":2438},"next-steps-enhance-your-server","Next Steps: Enhance Your Server",[10,2441,2442],{},"Ready to take your weather server to the next level? Here are some ideas:",[97,2444,2446],{"id":2445},"additional-weather-tools","🚀 Additional Weather Tools",[10,2448,2449],{},[22,2450,2451],{},"Extended Forecasts",[105,2453,2455],{"className":397,"code":2454,"language":399,"meta":110,"style":110},"server.tool('get-forecast', 'Get 7-day weather forecast', ...)\n",[112,2456,2457],{"__ignoreMap":110},[115,2458,2459,2461,2463,2465,2468,2470,2473,2475,2478],{"class":117,"line":118},[115,2460,523],{"class":194},[115,2462,526],{"class":121},[115,2464,565],{"class":194},[115,2466,2467],{"class":125},"'get-forecast'",[115,2469,1425],{"class":194},[115,2471,2472],{"class":125},"'Get 7-day weather forecast'",[115,2474,1425],{"class":194},[115,2476,2477],{"class":406},"...",[115,2479,571],{"class":194},[10,2481,2482],{},[22,2483,2484],{},"Weather Alerts",[105,2486,2488],{"className":397,"code":2487,"language":399,"meta":110,"style":110},"server.tool('get-alerts', 'Get severe weather warnings', ...)\n",[112,2489,2490],{"__ignoreMap":110},[115,2491,2492,2494,2496,2498,2501,2503,2506,2508,2510],{"class":117,"line":118},[115,2493,523],{"class":194},[115,2495,526],{"class":121},[115,2497,565],{"class":194},[115,2499,2500],{"class":125},"'get-alerts'",[115,2502,1425],{"class":194},[115,2504,2505],{"class":125},"'Get severe weather warnings'",[115,2507,1425],{"class":194},[115,2509,2477],{"class":406},[115,2511,571],{"class":194},[10,2513,2514],{},[22,2515,2516],{},"Air Quality",[105,2518,2520],{"className":397,"code":2519,"language":399,"meta":110,"style":110},"server.tool('get-air-quality', 'Get air pollution data', ...)\n",[112,2521,2522],{"__ignoreMap":110},[115,2523,2524,2526,2528,2530,2533,2535,2538,2540,2542],{"class":117,"line":118},[115,2525,523],{"class":194},[115,2527,526],{"class":121},[115,2529,565],{"class":194},[115,2531,2532],{"class":125},"'get-air-quality'",[115,2534,1425],{"class":194},[115,2536,2537],{"class":125},"'Get air pollution data'",[115,2539,1425],{"class":194},[115,2541,2477],{"class":406},[115,2543,571],{"class":194},[97,2545,2547],{"id":2546},"sharing-your-server","📦 Sharing Your Server",[26,2549,2550],{},[29,2551,2552,2555],{},[22,2553,2554],{},"Publish to NPM:"," Make it available for others to use",[61,2557,2559],{"id":2558},"conclusion","Conclusion",[10,2561,1025,2562,2564],{},[22,2563,1028],{}," You've successfully built your first MCP weather server!",[10,2566,2567],{},[22,2568,2569],{},"What You've Accomplished:",[26,2571,2572,2575,2578,2581],{},[29,2573,2574],{},"✅ Created a functional MCP server from scratch",[29,2576,2577],{},"✅ Integrated real-time weather data from an external API",[29,2579,2580],{},"✅ Connected it to VS Code and GitHub Copilot",[29,2582,2583],{},"✅ Learned the fundamentals of the Model Context Protocol",[10,2585,2586],{},[22,2587,2588],{},"Key Takeaways:",[26,2590,2591,2597,2603,2609],{},[29,2592,2593,2596],{},[22,2594,2595],{},"Simplicity:"," MCP servers are much easier to build than they appear",[29,2598,2599,2602],{},[22,2600,2601],{},"Power:"," Real data makes AI interactions dramatically more valuable",[29,2604,2605,2608],{},[22,2606,2607],{},"Flexibility:"," The same server works across multiple AI platforms",[29,2610,2611,2614],{},[22,2612,2613],{},"Future-ready:"," You're building the infrastructure for next-gen AI",[10,2616,2617,2620],{},[22,2618,2619],{},"What's Next?"," The possibilities are endless! Weather was just the beginning, now you can connect AI to databases, APIs, file systems, and any service you can imagine.",[10,2622,2623],{},"Happy building! 🚀",[61,2625,2627],{"id":2626},"resources-and-further-reading","📚 Resources and Further Reading",[10,2629,2630],{},[22,2631,2632],{},"Official Documentation",[26,2634,2635,2643,2650,2657,2664,2671],{},[29,2636,2637,2642],{},[1158,2638,2641],{"href":2639,"rel":2640},"https://modelcontextprotocol.io/",[1162],"Model Context Protocol Documentation"," - Complete MCP reference",[29,2644,2645],{},[1158,2646,2649],{"href":2647,"rel":2648},"https://github.com/modelcontextprotocol/typescript-sdk",[1162],"TypeScript SDK",[29,2651,2652],{},[1158,2653,2656],{"href":2654,"rel":2655},"https://github.com/modelcontextprotocol/python-sdk",[1162],"Python SDK",[29,2658,2659],{},[1158,2660,2663],{"href":2661,"rel":2662},"https://github.com/modelcontextprotocol/java-sdk",[1162],"Java SDK",[29,2665,2666],{},[1158,2667,2670],{"href":2668,"rel":2669},"https://github.com/modelcontextprotocol/kotlin-sdk",[1162],"Kotlin SDK",[29,2672,2673],{},[1158,2674,2677],{"href":2675,"rel":2676},"https://github.com/modelcontextprotocol/csharp-sdk",[1162],"C# SDK",[10,2679,2680],{},[22,2681,2682],{},"APIs Used in This Tutorial",[26,2684,2685,2692],{},[29,2686,2687,2691],{},[1158,2688,2690],{"href":1160,"rel":2689},[1162],"Open-Meteo Weather API"," - Free weather data service",[29,2693,2694,2699],{},[1158,2695,2698],{"href":2696,"rel":2697},"https://zod.dev/",[1162],"Zod Documentation"," - TypeScript schema validation",[10,2701,2702],{},[22,2703,2704],{},"MCP Examples",[26,2706,2707,2715,2723],{},[29,2708,2709,2714],{},[1158,2710,2713],{"href":2711,"rel":2712},"https://github.com/modelcontextprotocol/servers",[1162],"MCP Examples Repository"," - Sample servers",[29,2716,2717,2722],{},[1158,2718,2721],{"href":2719,"rel":2720},"https://github.com/microsoft/playwright-mcp",[1162],"Playwright MCP"," - Provides browser automation capabilities using Playwright.",[29,2724,2725],{},[1158,2726,2729],{"href":2727,"rel":2728},"https://docs.github.com/en/copilot/how-tos/context/model-context-protocol/using-the-github-mcp-server",[1162],"GitHub MCP",[10,2731,2732,678,2735],{},[22,2733,2734],{},"Demo Repo",[1158,2736,2739],{"href":2737,"rel":2738},"https://github.com/debs-obrien/mcp-weather-server-demo",[1162],"Demo available on GitHub",[10,2741,2742],{},[22,2743,2744],{},"Watch the Video",[10,2746,2747],{},[1158,2748,2751],{"href":2749,"rel":2750},"https://www.youtube.com/watch?v=egVm_z1nnnQ",[1162],"Build your first MCP Server: Tutorial for Beginners.",[10,2753,2754,2755],{},"Shoutout to Miguel Angel Duran for his great course and explanation. Check out his video in Spanish for a similar demo: ",[1158,2756,2759],{"href":2757,"rel":2758},"https://youtu.be/wnHczxwukYY?si=6TlZiYpc_XKkn46v",[1162],"Learn MCP! For Beginners + Create Our First MCP From Scratch\"",[2761,2762,2763],"style",{},"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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":110,"searchDepth":129,"depth":129,"links":2765},[2766,2767,2772,2776,2783,2787,2792,2796,2797,2798,2802,2803],{"id":63,"depth":129,"text":64},{"id":91,"depth":129,"text":92,"children":2768},[2769,2770,2771],{"id":99,"depth":138,"text":100},{"id":150,"depth":138,"text":151},{"id":170,"depth":138,"text":171},{"id":288,"depth":129,"text":289,"children":2773},[2774,2775],{"id":295,"depth":138,"text":296},{"id":317,"depth":138,"text":318},{"id":382,"depth":129,"text":383,"children":2777},[2778,2779,2780,2781,2782],{"id":393,"depth":138,"text":394},{"id":450,"depth":138,"text":451},{"id":505,"depth":138,"text":506},{"id":725,"depth":138,"text":726},{"id":793,"depth":138,"text":794},{"id":1032,"depth":129,"text":1033,"children":2784},[2785,2786],{"id":1039,"depth":138,"text":1040},{"id":1096,"depth":138,"text":1097},{"id":1152,"depth":129,"text":1153,"children":2788},[2789,2790,2791],{"id":1167,"depth":138,"text":1168},{"id":1188,"depth":138,"text":1189},{"id":1646,"depth":138,"text":1647},{"id":1673,"depth":129,"text":1674,"children":2793},[2794,2795],{"id":1680,"depth":138,"text":1681},{"id":1836,"depth":138,"text":1837},{"id":1908,"depth":129,"text":1909},{"id":1967,"depth":129,"text":1968},{"id":2438,"depth":129,"text":2439,"children":2799},[2800,2801],{"id":2445,"depth":138,"text":2446},{"id":2546,"depth":138,"text":2547},{"id":2558,"depth":129,"text":2559},{"id":2626,"depth":129,"text":2627},"https://dev.to/debs_obrien/building-your-first-mcp-server-a-beginners-tutorial-5fag","2025-07-01","Have you ever wanted your AI assistant to access real-time data? Model Context Protocol (MCP) servers make this possible, and they're surprisingly simple to build and use! Learn how to build an MCP server from scratch using TypeScript, connect it to a real weather API, and integrate it with VS Code and GitHub Copilot.","md",null,{"loading":2810},"eager","/blog/building-your-first-mcp-server-a-beginners-tutorial",{"title":5,"description":2806},"blog/building-your-first-mcp-server-a-beginners-tutorial",[2815,2816,2817,399],"mcp","webdev","ai","Xn69KvPoAFcDPry5U0V-h7OCswm0-vRzAhZWCOuEXuM",[2820,2824],{"title":2821,"path":2822,"stem":2823,"children":-1},"Automating Form Submissions with Playwright MCP and a Prompt file","/blog/automating-form-submissions-with-playwright-mcp-and-a-prompt-file","blog/automating-form-submissions-with-playwright-mcp-and-a-prompt-file",{"title":2825,"path":2826,"stem":2827,"children":-1},"Vibe Coding with Copilot and Gemini 2.5 pro - Simplifying My Blog with AI-Assisted Refactoring","/blog/vibe-coding-with-copilot-and-gemini","blog/vibe-coding-with-copilot-and-gemini",1790839746317]