[{"data":1,"prerenderedAt":1830},["ShallowReactive",2],{"blog-\u002Fblog\u002Fprogramowanie\u002Fserwer-mcp-typescript":3,"blog-others-\u002Fblog\u002Fprogramowanie\u002Fserwer-mcp-typescript":1793},{"id":4,"title":5,"body":6,"category":1780,"cover":1781,"date":1782,"description":1783,"extension":1784,"meta":1785,"navigation":139,"path":1786,"readingTime":1787,"seo":1788,"sitemap":1789,"stem":1790,"updated":1791,"__hash__":1792},"blog\u002Fblog\u002Fprogramowanie\u002Fserwer-mcp-typescript.md","Serwer MCP w TypeScript dla Claude Code, Codex i Copilot",{"type":7,"value":8,"toc":1750},"minimark",[9,13,18,21,33,36,40,47,1179,1182,1223,1233,1237,1240,1289,1300,1304,1307,1312,1373,1395,1399,1441,1448,1452,1463,1557,1563,1567,1574,1645,1667,1671,1677,1685,1689,1714,1718,1722,1725,1729,1732,1736,1739,1746],[10,11,12],"p",{},"Agent AI w edytorze zna Twój kod, ale nie zna Twojej aplikacji. Nie wie, jak utworzyć w niej rekord ani gdzie sprawdzić ranking. Serwer MCP (Model Context Protocol) to mały program, który mu to umożliwia, bo udostępnia funkcje aplikacji jako narzędzia z opisem i schematem argumentów. Pokażę Ci taki serwer w TypeScript na przykładzie aplikacji z quizami z kursu DevChallenge. Potem podłączymy go do Claude Code, Codex i Copilot w VS Code, bez zmieniania w nim ani jednej linijki.",[14,15,17],"h2",{"id":16},"jak-działa-lokalny-serwer-mcp","Co to jest serwer MCP i jak działa",[10,19,20],{},"Serwer MCP pośredniczy między agentem AI a Twoją aplikacją. Agent pobiera od niego listę narzędzi, a potem wywołuje te, których potrzebuje, z argumentami zgodnymi ze schematem. W MCP są trzy role. Host to aplikacja, w której rozmawiasz z modelem, na przykład Claude Code. Klient to część hosta, która utrzymuje połączenie z jednym serwerem. Serwer to Twój program z narzędziami.",[10,22,23,24,28,29,32],{},"Najprostszy transport to stdio. Host uruchamia serwer jako osobny proces i wymienia z nim wiadomości JSON-RPC przez standardowe wejście i wyjście. Wynika z tego jedna praktyczna zasada: stdout należy do protokołu. Każdy ",[25,26,27],"code",{},"console.log"," w serwerze może zepsuć komunikację, dlatego logi wypisujesz na stderr przez ",[25,30,31],{},"console.error",".",[10,34,35],{},"Taki serwer nie potrzebuje publicznego adresu, certyfikatu ani logowania. Działa na Twoim komputerze i kończy pracę razem z sesją agenta.",[14,37,39],{"id":38},"narzędzie-mcp-w-typescript","Narzędzie MCP w TypeScript",[10,41,42,43,46],{},"Serwer z kursu korzysta z oficjalnego SDK MCP w wersji 2, czyli z pakietu ",[25,44,45],{},"@modelcontextprotocol\u002Fserver",", i z Zod. Poniżej jest skrócona wersja jego narzędzia, które tworzy i publikuje quiz:",[48,49,54],"pre",{"className":50,"code":51,"language":52,"meta":53,"style":53},"language-ts shiki shiki-themes one-dark-pro","import { randomUUID } from 'node:crypto'\nimport { McpServer } from '@modelcontextprotocol\u002Fserver'\nimport { serveStdio } from '@modelcontextprotocol\u002Fserver\u002Fstdio'\nimport { z } from 'zod'\n\nconst apiUrl = new URL(process.env.DEVCHALLENGE_API_URL ?? 'http:\u002F\u002Flocalhost:3000')\n\nconst postJson = async (path: string, payload: object) => {\n  const response = await fetch(new URL(path, apiUrl), {\n    method: 'POST',\n    headers: { 'Content-Type': 'application\u002Fjson', Origin: apiUrl.origin },\n    body: JSON.stringify(payload),\n    signal: AbortSignal.timeout(75_000),\n  })\n  if (!response.ok) throw new Error(`Żądanie ${path} zwróciło status ${response.status}.`)\n  return response.json()\n}\n\nconst server = new McpServer({ name: 'devchallenge', version: '1.0.0' })\n\nserver.registerTool(\n  'create-challenge',\n  {\n    title: 'Stwórz challenge DevChallenge',\n    description:\n      'Generuje quiz przez AI i publikuje go pod publicznym linkiem. ' +\n      'Wywołanie kosztuje generację AI, więc potwierdź je w hoście.',\n    inputSchema: z.object({\n      topic: z.string().trim().min(1).max(200),\n      level: z.enum(['easy', 'medium', 'hard']),\n      questionCount: z.number().int().min(3).max(10),\n      typeMode: z.enum(['single', 'trueFalse', 'multiple']).default('single'),\n    }),\n    annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n  },\n  async ({ topic, level, questionCount, typeMode }) => {\n    try {\n      const challenge = await postJson('\u002Fapi\u002Fchallenges\u002Fgenerate', {\n        topic,\n        level,\n        questionCount,\n        typeMode,\n        documentId: null,\n        documentToken: null,\n        hasAiConsent: false,\n      })\n      const saved = await postJson('\u002Fapi\u002Fchallenges', { publicationId: randomUUID(), challenge })\n      return { content: [{ type: 'text', text: `Challenge gotowy: ${apiUrl.origin}\u002Fc\u002F${saved.id}` }] }\n    } catch (error) {\n      const message = error instanceof Error ? error.message : 'Nie udało się utworzyć quizu.'\n      return { content: [{ type: 'text', text: message }], isError: true }\n    }\n  },\n)\n\nserveStdio(() => server)\nconsole.error('DevChallenge MCP działa, stdout należy do protokołu.')\n","ts","",[25,55,56,83,100,117,134,141,187,192,238,274,288,322,345,369,375,436,452,458,463,502,507,521,529,535,548,557,566,574,591,634,668,708,749,755,792,798,832,840,863,871,879,887,895,908,920,932,938,975,1038,1055,1089,1127,1133,1138,1143,1148,1162],{"__ignoreMap":53},[57,58,61,65,69,73,76,79],"span",{"class":59,"line":60},"line",1,[57,62,64],{"class":63},"seHd6","import",[57,66,68],{"class":67},"sn6KH"," { ",[57,70,72],{"class":71},"sVyAn","randomUUID",[57,74,75],{"class":67}," } ",[57,77,78],{"class":63},"from",[57,80,82],{"class":81},"subq3"," 'node:crypto'\n",[57,84,86,88,90,93,95,97],{"class":59,"line":85},2,[57,87,64],{"class":63},[57,89,68],{"class":67},[57,91,92],{"class":71},"McpServer",[57,94,75],{"class":67},[57,96,78],{"class":63},[57,98,99],{"class":81}," '@modelcontextprotocol\u002Fserver'\n",[57,101,103,105,107,110,112,114],{"class":59,"line":102},3,[57,104,64],{"class":63},[57,106,68],{"class":67},[57,108,109],{"class":71},"serveStdio",[57,111,75],{"class":67},[57,113,78],{"class":63},[57,115,116],{"class":81}," '@modelcontextprotocol\u002Fserver\u002Fstdio'\n",[57,118,120,122,124,127,129,131],{"class":59,"line":119},4,[57,121,64],{"class":63},[57,123,68],{"class":67},[57,125,126],{"class":71},"z",[57,128,75],{"class":67},[57,130,78],{"class":63},[57,132,133],{"class":81}," 'zod'\n",[57,135,137],{"class":59,"line":136},5,[57,138,140],{"emptyLinePlaceholder":139},true,"\n",[57,142,144,147,151,155,158,162,165,168,170,173,175,178,181,184],{"class":59,"line":143},6,[57,145,146],{"class":63},"const",[57,148,150],{"class":149},"sU0A5"," apiUrl",[57,152,154],{"class":153},"sjrmR"," =",[57,156,157],{"class":63}," new",[57,159,161],{"class":160},"sVbv2"," URL",[57,163,164],{"class":67},"(",[57,166,167],{"class":149},"process",[57,169,32],{"class":67},[57,171,172],{"class":149},"env",[57,174,32],{"class":67},[57,176,177],{"class":71},"DEVCHALLENGE_API_URL",[57,179,180],{"class":153}," ??",[57,182,183],{"class":81}," 'http:\u002F\u002Flocalhost:3000'",[57,185,186],{"class":67},")\n",[57,188,190],{"class":59,"line":189},7,[57,191,140],{"emptyLinePlaceholder":139},[57,193,195,197,200,202,205,208,212,215,218,221,224,226,229,232,235],{"class":59,"line":194},8,[57,196,146],{"class":63},[57,198,199],{"class":160}," postJson",[57,201,154],{"class":153},[57,203,204],{"class":63}," async",[57,206,207],{"class":67}," (",[57,209,211],{"class":210},"s_ZVi","path",[57,213,214],{"class":67},": ",[57,216,217],{"class":149},"string",[57,219,220],{"class":67},", ",[57,222,223],{"class":210},"payload",[57,225,214],{"class":67},[57,227,228],{"class":149},"object",[57,230,231],{"class":67},") ",[57,233,234],{"class":63},"=>",[57,236,237],{"class":67}," {\n",[57,239,241,244,247,249,252,255,257,260,262,264,266,268,271],{"class":59,"line":240},9,[57,242,243],{"class":63},"  const",[57,245,246],{"class":149}," response",[57,248,154],{"class":153},[57,250,251],{"class":63}," await",[57,253,254],{"class":160}," fetch",[57,256,164],{"class":67},[57,258,259],{"class":63},"new",[57,261,161],{"class":160},[57,263,164],{"class":67},[57,265,211],{"class":71},[57,267,220],{"class":67},[57,269,270],{"class":71},"apiUrl",[57,272,273],{"class":67},"), {\n",[57,275,277,280,282,285],{"class":59,"line":276},10,[57,278,279],{"class":71},"    method",[57,281,214],{"class":67},[57,283,284],{"class":81},"'POST'",[57,286,287],{"class":67},",\n",[57,289,291,294,297,300,302,305,307,310,312,314,316,319],{"class":59,"line":290},11,[57,292,293],{"class":71},"    headers",[57,295,296],{"class":67},": { ",[57,298,299],{"class":81},"'Content-Type'",[57,301,214],{"class":67},[57,303,304],{"class":81},"'application\u002Fjson'",[57,306,220],{"class":67},[57,308,309],{"class":71},"Origin",[57,311,214],{"class":67},[57,313,270],{"class":149},[57,315,32],{"class":67},[57,317,318],{"class":71},"origin",[57,320,321],{"class":67}," },\n",[57,323,325,328,330,333,335,338,340,342],{"class":59,"line":324},12,[57,326,327],{"class":71},"    body",[57,329,214],{"class":67},[57,331,332],{"class":149},"JSON",[57,334,32],{"class":67},[57,336,337],{"class":160},"stringify",[57,339,164],{"class":67},[57,341,223],{"class":71},[57,343,344],{"class":67},"),\n",[57,346,348,351,353,356,358,361,363,367],{"class":59,"line":347},13,[57,349,350],{"class":71},"    signal",[57,352,214],{"class":67},[57,354,355],{"class":149},"AbortSignal",[57,357,32],{"class":67},[57,359,360],{"class":160},"timeout",[57,362,164],{"class":67},[57,364,366],{"class":365},"sVC51","75_000",[57,368,344],{"class":67},[57,370,372],{"class":59,"line":371},14,[57,373,374],{"class":67},"  })\n",[57,376,378,381,383,386,389,391,394,396,399,401,404,406,409,412,414,417,420,422,424,426,429,431,434],{"class":59,"line":377},15,[57,379,380],{"class":63},"  if",[57,382,207],{"class":67},[57,384,385],{"class":153},"!",[57,387,388],{"class":149},"response",[57,390,32],{"class":67},[57,392,393],{"class":71},"ok",[57,395,231],{"class":67},[57,397,398],{"class":63},"throw",[57,400,157],{"class":63},[57,402,403],{"class":160}," Error",[57,405,164],{"class":67},[57,407,408],{"class":81},"`Żądanie ",[57,410,411],{"class":63},"${",[57,413,211],{"class":71},[57,415,416],{"class":63},"}",[57,418,419],{"class":81}," zwróciło status ",[57,421,411],{"class":63},[57,423,388],{"class":149},[57,425,32],{"class":67},[57,427,428],{"class":71},"status",[57,430,416],{"class":63},[57,432,433],{"class":81},".`",[57,435,186],{"class":67},[57,437,439,442,444,446,449],{"class":59,"line":438},16,[57,440,441],{"class":63},"  return",[57,443,246],{"class":149},[57,445,32],{"class":67},[57,447,448],{"class":160},"json",[57,450,451],{"class":67},"()\n",[57,453,455],{"class":59,"line":454},17,[57,456,457],{"class":67},"}\n",[57,459,461],{"class":59,"line":460},18,[57,462,140],{"emptyLinePlaceholder":139},[57,464,466,468,471,473,475,478,481,484,486,489,491,494,496,499],{"class":59,"line":465},19,[57,467,146],{"class":63},[57,469,470],{"class":149}," server",[57,472,154],{"class":153},[57,474,157],{"class":63},[57,476,477],{"class":160}," McpServer",[57,479,480],{"class":67},"({ ",[57,482,483],{"class":71},"name",[57,485,214],{"class":67},[57,487,488],{"class":81},"'devchallenge'",[57,490,220],{"class":67},[57,492,493],{"class":71},"version",[57,495,214],{"class":67},[57,497,498],{"class":81},"'1.0.0'",[57,500,501],{"class":67}," })\n",[57,503,505],{"class":59,"line":504},20,[57,506,140],{"emptyLinePlaceholder":139},[57,508,510,513,515,518],{"class":59,"line":509},21,[57,511,512],{"class":149},"server",[57,514,32],{"class":67},[57,516,517],{"class":160},"registerTool",[57,519,520],{"class":67},"(\n",[57,522,524,527],{"class":59,"line":523},22,[57,525,526],{"class":81},"  'create-challenge'",[57,528,287],{"class":67},[57,530,532],{"class":59,"line":531},23,[57,533,534],{"class":67},"  {\n",[57,536,538,541,543,546],{"class":59,"line":537},24,[57,539,540],{"class":71},"    title",[57,542,214],{"class":67},[57,544,545],{"class":81},"'Stwórz challenge DevChallenge'",[57,547,287],{"class":67},[57,549,551,554],{"class":59,"line":550},25,[57,552,553],{"class":71},"    description",[57,555,556],{"class":67},":\n",[57,558,560,563],{"class":59,"line":559},26,[57,561,562],{"class":81},"      'Generuje quiz przez AI i publikuje go pod publicznym linkiem. '",[57,564,565],{"class":153}," +\n",[57,567,569,572],{"class":59,"line":568},27,[57,570,571],{"class":81},"      'Wywołanie kosztuje generację AI, więc potwierdź je w hoście.'",[57,573,287],{"class":67},[57,575,577,580,582,584,586,588],{"class":59,"line":576},28,[57,578,579],{"class":71},"    inputSchema",[57,581,214],{"class":67},[57,583,126],{"class":149},[57,585,32],{"class":67},[57,587,228],{"class":160},[57,589,590],{"class":67},"({\n",[57,592,594,597,599,601,603,605,608,611,613,616,618,621,624,627,629,632],{"class":59,"line":593},29,[57,595,596],{"class":71},"      topic",[57,598,214],{"class":67},[57,600,126],{"class":149},[57,602,32],{"class":67},[57,604,217],{"class":160},[57,606,607],{"class":67},"().",[57,609,610],{"class":160},"trim",[57,612,607],{"class":67},[57,614,615],{"class":160},"min",[57,617,164],{"class":67},[57,619,620],{"class":365},"1",[57,622,623],{"class":67},").",[57,625,626],{"class":160},"max",[57,628,164],{"class":67},[57,630,631],{"class":365},"200",[57,633,344],{"class":67},[57,635,637,640,642,644,646,649,652,655,657,660,662,665],{"class":59,"line":636},30,[57,638,639],{"class":71},"      level",[57,641,214],{"class":67},[57,643,126],{"class":149},[57,645,32],{"class":67},[57,647,648],{"class":160},"enum",[57,650,651],{"class":67},"([",[57,653,654],{"class":81},"'easy'",[57,656,220],{"class":67},[57,658,659],{"class":81},"'medium'",[57,661,220],{"class":67},[57,663,664],{"class":81},"'hard'",[57,666,667],{"class":67},"]),\n",[57,669,671,674,676,678,680,683,685,688,690,692,694,697,699,701,703,706],{"class":59,"line":670},31,[57,672,673],{"class":71},"      questionCount",[57,675,214],{"class":67},[57,677,126],{"class":149},[57,679,32],{"class":67},[57,681,682],{"class":160},"number",[57,684,607],{"class":67},[57,686,687],{"class":160},"int",[57,689,607],{"class":67},[57,691,615],{"class":160},[57,693,164],{"class":67},[57,695,696],{"class":365},"3",[57,698,623],{"class":67},[57,700,626],{"class":160},[57,702,164],{"class":67},[57,704,705],{"class":365},"10",[57,707,344],{"class":67},[57,709,711,714,716,718,720,722,724,727,729,732,734,737,740,743,745,747],{"class":59,"line":710},32,[57,712,713],{"class":71},"      typeMode",[57,715,214],{"class":67},[57,717,126],{"class":149},[57,719,32],{"class":67},[57,721,648],{"class":160},[57,723,651],{"class":67},[57,725,726],{"class":81},"'single'",[57,728,220],{"class":67},[57,730,731],{"class":81},"'trueFalse'",[57,733,220],{"class":67},[57,735,736],{"class":81},"'multiple'",[57,738,739],{"class":67},"]).",[57,741,742],{"class":160},"default",[57,744,164],{"class":67},[57,746,726],{"class":81},[57,748,344],{"class":67},[57,750,752],{"class":59,"line":751},33,[57,753,754],{"class":67},"    }),\n",[57,756,758,761,763,766,768,771,773,776,778,780,782,785,787,790],{"class":59,"line":757},34,[57,759,760],{"class":71},"    annotations",[57,762,296],{"class":67},[57,764,765],{"class":71},"readOnlyHint",[57,767,214],{"class":67},[57,769,770],{"class":365},"false",[57,772,220],{"class":67},[57,774,775],{"class":71},"destructiveHint",[57,777,214],{"class":67},[57,779,770],{"class":365},[57,781,220],{"class":67},[57,783,784],{"class":71},"openWorldHint",[57,786,214],{"class":67},[57,788,789],{"class":365},"true",[57,791,321],{"class":67},[57,793,795],{"class":59,"line":794},35,[57,796,797],{"class":67},"  },\n",[57,799,801,804,807,810,812,815,817,820,822,825,828,830],{"class":59,"line":800},36,[57,802,803],{"class":63},"  async",[57,805,806],{"class":67}," ({ ",[57,808,809],{"class":210},"topic",[57,811,220],{"class":67},[57,813,814],{"class":210},"level",[57,816,220],{"class":67},[57,818,819],{"class":210},"questionCount",[57,821,220],{"class":67},[57,823,824],{"class":210},"typeMode",[57,826,827],{"class":67}," }) ",[57,829,234],{"class":63},[57,831,237],{"class":67},[57,833,835,838],{"class":59,"line":834},37,[57,836,837],{"class":63},"    try",[57,839,237],{"class":67},[57,841,843,846,849,851,853,855,857,860],{"class":59,"line":842},38,[57,844,845],{"class":63},"      const",[57,847,848],{"class":149}," challenge",[57,850,154],{"class":153},[57,852,251],{"class":63},[57,854,199],{"class":160},[57,856,164],{"class":67},[57,858,859],{"class":81},"'\u002Fapi\u002Fchallenges\u002Fgenerate'",[57,861,862],{"class":67},", {\n",[57,864,866,869],{"class":59,"line":865},39,[57,867,868],{"class":71},"        topic",[57,870,287],{"class":67},[57,872,874,877],{"class":59,"line":873},40,[57,875,876],{"class":71},"        level",[57,878,287],{"class":67},[57,880,882,885],{"class":59,"line":881},41,[57,883,884],{"class":71},"        questionCount",[57,886,287],{"class":67},[57,888,890,893],{"class":59,"line":889},42,[57,891,892],{"class":71},"        typeMode",[57,894,287],{"class":67},[57,896,898,901,903,906],{"class":59,"line":897},43,[57,899,900],{"class":71},"        documentId",[57,902,214],{"class":67},[57,904,905],{"class":365},"null",[57,907,287],{"class":67},[57,909,911,914,916,918],{"class":59,"line":910},44,[57,912,913],{"class":71},"        documentToken",[57,915,214],{"class":67},[57,917,905],{"class":365},[57,919,287],{"class":67},[57,921,923,926,928,930],{"class":59,"line":922},45,[57,924,925],{"class":71},"        hasAiConsent",[57,927,214],{"class":67},[57,929,770],{"class":365},[57,931,287],{"class":67},[57,933,935],{"class":59,"line":934},46,[57,936,937],{"class":67},"      })\n",[57,939,941,943,946,948,950,952,954,957,960,963,965,967,970,973],{"class":59,"line":940},47,[57,942,845],{"class":63},[57,944,945],{"class":149}," saved",[57,947,154],{"class":153},[57,949,251],{"class":63},[57,951,199],{"class":160},[57,953,164],{"class":67},[57,955,956],{"class":81},"'\u002Fapi\u002Fchallenges'",[57,958,959],{"class":67},", { ",[57,961,962],{"class":71},"publicationId",[57,964,214],{"class":67},[57,966,72],{"class":160},[57,968,969],{"class":67},"(), ",[57,971,972],{"class":71},"challenge",[57,974,501],{"class":67},[57,976,978,981,983,986,989,992,994,997,999,1002,1004,1007,1009,1011,1013,1015,1017,1020,1022,1025,1027,1030,1032,1035],{"class":59,"line":977},48,[57,979,980],{"class":63},"      return",[57,982,68],{"class":67},[57,984,985],{"class":71},"content",[57,987,988],{"class":67},": [{ ",[57,990,991],{"class":71},"type",[57,993,214],{"class":67},[57,995,996],{"class":81},"'text'",[57,998,220],{"class":67},[57,1000,1001],{"class":71},"text",[57,1003,214],{"class":67},[57,1005,1006],{"class":81},"`Challenge gotowy: ",[57,1008,411],{"class":63},[57,1010,270],{"class":149},[57,1012,32],{"class":67},[57,1014,318],{"class":71},[57,1016,416],{"class":63},[57,1018,1019],{"class":81},"\u002Fc\u002F",[57,1021,411],{"class":63},[57,1023,1024],{"class":149},"saved",[57,1026,32],{"class":67},[57,1028,1029],{"class":71},"id",[57,1031,416],{"class":63},[57,1033,1034],{"class":81},"`",[57,1036,1037],{"class":67}," }] }\n",[57,1039,1041,1044,1047,1049,1052],{"class":59,"line":1040},49,[57,1042,1043],{"class":67},"    } ",[57,1045,1046],{"class":63},"catch",[57,1048,207],{"class":67},[57,1050,1051],{"class":71},"error",[57,1053,1054],{"class":67},") {\n",[57,1056,1058,1060,1063,1065,1068,1071,1073,1076,1078,1080,1083,1086],{"class":59,"line":1057},50,[57,1059,845],{"class":63},[57,1061,1062],{"class":149}," message",[57,1064,154],{"class":153},[57,1066,1067],{"class":71}," error",[57,1069,1070],{"class":63}," instanceof",[57,1072,403],{"class":149},[57,1074,1075],{"class":63}," ?",[57,1077,1067],{"class":149},[57,1079,32],{"class":67},[57,1081,1082],{"class":71},"message",[57,1084,1085],{"class":63}," :",[57,1087,1088],{"class":81}," 'Nie udało się utworzyć quizu.'\n",[57,1090,1092,1094,1096,1098,1100,1102,1104,1106,1108,1110,1112,1114,1117,1120,1122,1124],{"class":59,"line":1091},51,[57,1093,980],{"class":63},[57,1095,68],{"class":67},[57,1097,985],{"class":71},[57,1099,988],{"class":67},[57,1101,991],{"class":71},[57,1103,214],{"class":67},[57,1105,996],{"class":81},[57,1107,220],{"class":67},[57,1109,1001],{"class":71},[57,1111,214],{"class":67},[57,1113,1082],{"class":71},[57,1115,1116],{"class":67}," }], ",[57,1118,1119],{"class":71},"isError",[57,1121,214],{"class":67},[57,1123,789],{"class":365},[57,1125,1126],{"class":67}," }\n",[57,1128,1130],{"class":59,"line":1129},52,[57,1131,1132],{"class":67},"    }\n",[57,1134,1136],{"class":59,"line":1135},53,[57,1137,797],{"class":67},[57,1139,1141],{"class":59,"line":1140},54,[57,1142,186],{"class":67},[57,1144,1146],{"class":59,"line":1145},55,[57,1147,140],{"emptyLinePlaceholder":139},[57,1149,1151,1153,1156,1158,1160],{"class":59,"line":1150},56,[57,1152,109],{"class":160},[57,1154,1155],{"class":67},"(() ",[57,1157,234],{"class":63},[57,1159,470],{"class":71},[57,1161,186],{"class":67},[57,1163,1165,1168,1170,1172,1174,1177],{"class":59,"line":1164},57,[57,1166,1167],{"class":149},"console",[57,1169,32],{"class":67},[57,1171,1051],{"class":160},[57,1173,164],{"class":67},[57,1175,1176],{"class":81},"'DevChallenge MCP działa, stdout należy do protokołu.'",[57,1178,186],{"class":67},[10,1180,1181],{},"W kursie serwer sprawdza jeszcze odpowiedź API schematem Zod, zanim cokolwiek opublikuje. Tutaj pominąłem ten krok, żeby kod zmieścił się na jednym ekranie. Kilka decyzji warto omówić osobno:",[1183,1184,1185,1193,1207,1217],"ul",{},[1186,1187,1188,1192],"li",{},[1189,1190,1191],"strong",{},"Opis mówi o koszcie."," Czyta go model, więc od tego opisu zależy, czy agent zapyta Cię o zgodę, zanim wywoła narzędzie.",[1186,1194,1195,1198,1199,1202,1203,1206],{},[1189,1196,1197],{},"Adnotacje informują hosta o skutkach."," ",[25,1200,1201],{},"readOnlyHint: false"," i ",[25,1204,1205],{},"openWorldHint: true"," oznaczają, że narzędzie zmienia stan i sięga poza Twój komputer. Host może więc poprosić Cię o potwierdzenie, ale adnotacja to tylko podpowiedź, a nie zabezpieczenie.",[1186,1208,1209,1212,1213,1216],{},[1189,1210,1211],{},"Błąd wraca jako wynik."," Zamiast rzucać wyjątek, narzędzie zwraca treść błędu z ",[25,1214,1215],{},"isError: true",". Model zobaczy wtedy na przykład status 429 przy limicie i przekaże Ci go, zamiast zgadywać.",[1186,1218,1219,1222],{},[1189,1220,1221],{},"Serwer zna tylko adres API."," Klucze OpenAI i dane dostępu do bazy danych zostają w aplikacji.",[10,1224,1225,1226,1229,1230,32],{},"Node.js 24 uruchamia pliki ",[25,1227,1228],{},".ts"," bezpośrednio, więc serwer nie potrzebuje osobnego kroku budowania. W repozytorium kursu wystarczy polecenie ",[25,1231,1232],{},"node mcp-server\u002Fsrc\u002Findex.ts",[14,1234,1236],{"id":1235},"najpierw-sprawdź-serwer-w-mcp-inspector","Najpierw sprawdź serwer w MCP Inspector",[10,1238,1239],{},"Zanim podłączysz agenta, sprawdź serwer w darmowym MCP Inspector. Uruchom aplikację w jednym terminalu, a w drugim pobierz listę narzędzi. W poleceniu wpisz własną ścieżkę do serwera:",[48,1241,1245],{"className":1242,"code":1243,"language":1244,"meta":53,"style":53},"language-bash shiki shiki-themes one-dark-pro","npx @modelcontextprotocol\u002Finspector --cli \\\n  -e DEVCHALLENGE_API_URL=http:\u002F\u002F127.0.0.1:3000 \\\n  node \u002FABSOLUTNA\u002FSCIEZKA\u002Fmcp-server\u002Fsrc\u002Findex.ts \\\n  --method tools\u002Flist\n","bash",[25,1246,1247,1261,1271,1281],{"__ignoreMap":53},[57,1248,1249,1252,1255,1258],{"class":59,"line":60},[57,1250,1251],{"class":160},"npx",[57,1253,1254],{"class":81}," @modelcontextprotocol\u002Finspector",[57,1256,1257],{"class":365}," --cli",[57,1259,1260],{"class":153}," \\\n",[57,1262,1263,1266,1269],{"class":59,"line":85},[57,1264,1265],{"class":365},"  -e",[57,1267,1268],{"class":81}," DEVCHALLENGE_API_URL=http:\u002F\u002F127.0.0.1:3000",[57,1270,1260],{"class":153},[57,1272,1273,1276,1279],{"class":59,"line":102},[57,1274,1275],{"class":81},"  node",[57,1277,1278],{"class":81}," \u002FABSOLUTNA\u002FSCIEZKA\u002Fmcp-server\u002Fsrc\u002Findex.ts",[57,1280,1260],{"class":153},[57,1282,1283,1286],{"class":59,"line":119},[57,1284,1285],{"class":365},"  --method",[57,1287,1288],{"class":81}," tools\u002Flist\n",[10,1290,1291,1292,1295,1296,1299],{},"Wynik powinien zawierać ",[25,1293,1294],{},"create-challenge"," razem ze schematem argumentów. Lista narzędzi niczego nie generuje, więc ten krok nic nie kosztuje. Bez ",[25,1297,1298],{},"--cli"," Inspector otworzy interfejs w przeglądarce, w którym wywołasz narzędzie ręcznie.",[14,1301,1303],{"id":1302},"ten-sam-serwer-w-claude-code-codexie-i-copilocie","Ten sam serwer w Claude Code, Codex i Copilot",[10,1305,1306],{},"Każdy agent potrzebuje tej samej informacji: jakim poleceniem uruchomić serwer i z jakimi zmiennymi środowiskowymi. Różni się tylko miejsce, w którym ją zapisujesz. Agenci zmieniają się szybko, więc przy błędzie zajrzyj do ich aktualnej dokumentacji.",[1308,1309,1311],"h3",{"id":1310},"claude-code","Claude Code",[48,1313,1315],{"className":1242,"code":1314,"language":1244,"meta":53,"style":53},"claude mcp add devchallenge \\\n  --transport stdio \\\n  --scope local \\\n  --env DEVCHALLENGE_API_URL=http:\u002F\u002F127.0.0.1:3000 \\\n  -- node \u002FABSOLUTNA\u002FSCIEZKA\u002Fmcp-server\u002Fsrc\u002Findex.ts\n",[25,1316,1317,1333,1343,1353,1362],{"__ignoreMap":53},[57,1318,1319,1322,1325,1328,1331],{"class":59,"line":60},[57,1320,1321],{"class":160},"claude",[57,1323,1324],{"class":81}," mcp",[57,1326,1327],{"class":81}," add",[57,1329,1330],{"class":81}," devchallenge",[57,1332,1260],{"class":153},[57,1334,1335,1338,1341],{"class":59,"line":85},[57,1336,1337],{"class":365},"  --transport",[57,1339,1340],{"class":81}," stdio",[57,1342,1260],{"class":153},[57,1344,1345,1348,1351],{"class":59,"line":102},[57,1346,1347],{"class":365},"  --scope",[57,1349,1350],{"class":81}," local",[57,1352,1260],{"class":153},[57,1354,1355,1358,1360],{"class":59,"line":119},[57,1356,1357],{"class":365},"  --env",[57,1359,1268],{"class":81},[57,1361,1260],{"class":153},[57,1363,1364,1367,1370],{"class":59,"line":136},[57,1365,1366],{"class":365},"  --",[57,1368,1369],{"class":81}," node",[57,1371,1372],{"class":81}," \u002FABSOLUTNA\u002FSCIEZKA\u002Fmcp-server\u002Fsrc\u002Findex.ts\n",[10,1374,1375,1376,1379,1380,1383,1384,1387,1388,1391,1392,32],{},"Nazwa serwera stoi zaraz po ",[25,1377,1378],{},"add",", bo opcja ",[25,1381,1382],{},"--env"," przyjmuje kilka wartości i wzięłaby nazwę za kolejną zmienną. W sesji Claude Code polecenie ",[25,1385,1386],{},"\u002Fmcp"," pokaże, czy serwer jest połączony. Jeśli agent uruchomi starszy Node niż 24, wpisz zamiast ",[25,1389,1390],{},"node"," pełną ścieżkę z polecenia ",[25,1393,1394],{},"node -p \"process.execPath\"",[1308,1396,1398],{"id":1397},"codex","Codex",[48,1400,1402],{"className":1242,"code":1401,"language":1244,"meta":53,"style":53},"codex mcp add devchallenge \\\n  --env DEVCHALLENGE_API_URL=http:\u002F\u002F127.0.0.1:3000 \\\n  -- node \u002FABSOLUTNA\u002FSCIEZKA\u002Fmcp-server\u002Fsrc\u002Findex.ts\ncodex mcp list\n",[25,1403,1404,1416,1424,1432],{"__ignoreMap":53},[57,1405,1406,1408,1410,1412,1414],{"class":59,"line":60},[57,1407,1397],{"class":160},[57,1409,1324],{"class":81},[57,1411,1327],{"class":81},[57,1413,1330],{"class":81},[57,1415,1260],{"class":153},[57,1417,1418,1420,1422],{"class":59,"line":85},[57,1419,1357],{"class":365},[57,1421,1268],{"class":81},[57,1423,1260],{"class":153},[57,1425,1426,1428,1430],{"class":59,"line":102},[57,1427,1366],{"class":365},[57,1429,1369],{"class":81},[57,1431,1372],{"class":81},[57,1433,1434,1436,1438],{"class":59,"line":119},[57,1435,1397],{"class":160},[57,1437,1324],{"class":81},[57,1439,1440],{"class":81}," list\n",[10,1442,1443,1444,1447],{},"Codex zapisuje ten wpis w swojej konfiguracji, w pliku ",[25,1445,1446],{},"~\u002F.codex\u002Fconfig.toml",". Drugie polecenie pokazuje listę serwerów, więc od razu sprawdzisz, czy wpis się zapisał.",[1308,1449,1451],{"id":1450},"copilot-w-vs-code","Copilot w VS Code",[10,1453,1454,1455,1458,1459,1462],{},"W katalogu projektu utwórz plik ",[25,1456,1457],{},".vscode\u002Fmcp.json",". Główny klucz to ",[25,1460,1461],{},"servers",":",[48,1464,1467],{"className":1465,"code":1466,"language":448,"meta":53,"style":53},"language-json shiki shiki-themes one-dark-pro","{\n  \"servers\": {\n    \"devchallenge\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\"${workspaceFolder}\u002Fmcp-server\u002Fsrc\u002Findex.ts\"],\n      \"env\": { \"DEVCHALLENGE_API_URL\": \"http:\u002F\u002F127.0.0.1:3000\" }\n    }\n  }\n}\n",[25,1468,1469,1474,1482,1489,1501,1513,1527,1544,1548,1553],{"__ignoreMap":53},[57,1470,1471],{"class":59,"line":60},[57,1472,1473],{"class":67},"{\n",[57,1475,1476,1479],{"class":59,"line":85},[57,1477,1478],{"class":71},"  \"servers\"",[57,1480,1481],{"class":67},": {\n",[57,1483,1484,1487],{"class":59,"line":102},[57,1485,1486],{"class":71},"    \"devchallenge\"",[57,1488,1481],{"class":67},[57,1490,1491,1494,1496,1499],{"class":59,"line":119},[57,1492,1493],{"class":71},"      \"type\"",[57,1495,214],{"class":67},[57,1497,1498],{"class":81},"\"stdio\"",[57,1500,287],{"class":67},[57,1502,1503,1506,1508,1511],{"class":59,"line":136},[57,1504,1505],{"class":71},"      \"command\"",[57,1507,214],{"class":67},[57,1509,1510],{"class":81},"\"node\"",[57,1512,287],{"class":67},[57,1514,1515,1518,1521,1524],{"class":59,"line":143},[57,1516,1517],{"class":71},"      \"args\"",[57,1519,1520],{"class":67},": [",[57,1522,1523],{"class":81},"\"${workspaceFolder}\u002Fmcp-server\u002Fsrc\u002Findex.ts\"",[57,1525,1526],{"class":67},"],\n",[57,1528,1529,1532,1534,1537,1539,1542],{"class":59,"line":189},[57,1530,1531],{"class":71},"      \"env\"",[57,1533,296],{"class":67},[57,1535,1536],{"class":71},"\"DEVCHALLENGE_API_URL\"",[57,1538,214],{"class":67},[57,1540,1541],{"class":81},"\"http:\u002F\u002F127.0.0.1:3000\"",[57,1543,1126],{"class":67},[57,1545,1546],{"class":59,"line":194},[57,1547,1132],{"class":67},[57,1549,1550],{"class":59,"line":240},[57,1551,1552],{"class":67},"  }\n",[57,1554,1555],{"class":59,"line":276},[57,1556,457],{"class":67},[10,1558,1559,1560,1562],{},"Potem otwórz Copilot Chat w trybie agenta i sprawdź na liście narzędzi, czy jest tam ",[25,1561,1294],{},". Jeśli korzystasz z GitHub Copilot na koncie firmowym, administrator organizacji może mieć wyłączone serwery MCP. Kiedy narzędzi nie widać, sprawdź najpierw to ustawienie.",[14,1564,1566],{"id":1565},"skill-projektu-kiedy-agent-ma-zapytać-o-zgodę","Skill w Claude Code i Codex: kiedy agent ma zapytać o zgodę",[10,1568,1569,1570,1573],{},"Konfiguracja mówi agentowi, jak uruchomić serwer, ale nie mówi, kiedy z niego korzystać. Do tego służy skill, czyli plik ",[25,1571,1572],{},"SKILL.md"," z krótką instrukcją i opisem, po którym agent rozpoznaje, że skill pasuje do zadania. Przykładowy skill dla tej aplikacji może wyglądać tak:",[48,1575,1579],{"className":1576,"code":1577,"language":1578,"meta":53,"style":53},"language-markdown shiki shiki-themes one-dark-pro","---\nname: devchallenge-quiz\ndescription: Tworzy quiz w lokalnej aplikacji DevChallenge przez narzędzie MCP create-challenge. Użyj, gdy ktoś prosi o quiz na wybrany temat.\n---\n\n1. Ustal temat i streść go w najwyżej 200 znakach.\n2. Pokaż argumenty: temat, poziom, liczbę pytań i typ pytań.\n3. Przed wywołaniem create-challenge poproś o potwierdzenie. Każde wywołanie kosztuje generację AI i publikuje quiz pod publicznym linkiem.\n4. Po błędzie nie ponawiaj wywołania bez zgody. Status 429 oznacza limit generowania.\n","markdown",[25,1580,1581,1586,1595,1605,1609,1613,1621,1629,1637],{"__ignoreMap":53},[57,1582,1583],{"class":59,"line":60},[57,1584,1585],{"class":67},"---\n",[57,1587,1588,1590,1592],{"class":59,"line":85},[57,1589,483],{"class":71},[57,1591,214],{"class":67},[57,1593,1594],{"class":81},"devchallenge-quiz\n",[57,1596,1597,1600,1602],{"class":59,"line":102},[57,1598,1599],{"class":71},"description",[57,1601,214],{"class":67},[57,1603,1604],{"class":81},"Tworzy quiz w lokalnej aplikacji DevChallenge przez narzędzie MCP create-challenge. Użyj, gdy ktoś prosi o quiz na wybrany temat.\n",[57,1606,1607],{"class":59,"line":119},[57,1608,1585],{"class":67},[57,1610,1611],{"class":59,"line":136},[57,1612,140],{"emptyLinePlaceholder":139},[57,1614,1615,1618],{"class":59,"line":143},[57,1616,1617],{"class":149},"1.",[57,1619,1620],{"class":67}," Ustal temat i streść go w najwyżej 200 znakach.\n",[57,1622,1623,1626],{"class":59,"line":189},[57,1624,1625],{"class":149},"2.",[57,1627,1628],{"class":67}," Pokaż argumenty: temat, poziom, liczbę pytań i typ pytań.\n",[57,1630,1631,1634],{"class":59,"line":194},[57,1632,1633],{"class":149},"3.",[57,1635,1636],{"class":67}," Przed wywołaniem create-challenge poproś o potwierdzenie. Każde wywołanie kosztuje generację AI i publikuje quiz pod publicznym linkiem.\n",[57,1638,1639,1642],{"class":59,"line":240},[57,1640,1641],{"class":149},"4.",[57,1643,1644],{"class":67}," Po błędzie nie ponawiaj wywołania bez zgody. Status 429 oznacza limit generowania.\n",[10,1646,1647,1648,1651,1652,1655,1656,1659,1660,1663,1664,32],{},"Claude Code szuka skilli w katalogu ",[25,1649,1650],{},".claude\u002Fskills",", Codex w ",[25,1653,1654],{},".agents\u002Fskills",", a Copilot w VS Code w obu tych miejscach. W repozytorium trzymasz więc skill w ",[25,1657,1658],{},".claude\u002Fskills\u002Fdevchallenge-quiz\u002FSKILL.md"," i jego kopię w ",[25,1661,1662],{},".agents\u002Fskills\u002Fdevchallenge-quiz\u002FSKILL.md",". Ogólne zasady projektu, na przykład polecenia testów, zapisujesz w ",[25,1665,1666],{},"AGENTS.md",[14,1668,1670],{"id":1669},"co-agent-naprawdę-robi-z-twoim-kodem","Co agent naprawdę robi z Twoim kodem",[10,1672,1673,1674,1676],{},"Poproś agenta: „zrób quiz o tym, jak działa nasz moduł RAG”. Agent przeczyta pliki projektu, streści temat do 200 znaków i wywoła ",[25,1675,1294],{},". Narzędzie nie dostaje ani kodu, ani PDF⁠-⁠a, tylko ten krótki temat. Quiz powstaje więc z tematu i wiedzy modelu, a nie z Twojego repozytorium.",[10,1678,1679,1680,32],{},"To nadal jest przydatne, bo agent trafnie nazywa temat na podstawie kodu. Warto jednak to wiedzieć, zanim komuś obiecasz „quiz z Twojego kodu”. Różnicę między takim narzędziem a quizem z dokumentu opisuję we wpisie ",[1681,1682,1684],"a",{"href":1683},"\u002Fblog\u002Fprogramowanie\u002Frag-vs-mcp","RAG vs MCP na przykładzie jednej aplikacji",[14,1686,1688],{"id":1687},"bezpieczeństwo-serwera-mcp-w-trzech-zasadach","Bezpieczeństwo serwera MCP w trzech zasadach",[1690,1691,1692,1698,1704],"ol",{},[1186,1693,1694,1697],{},[1189,1695,1696],{},"Serwer zna tylko publiczne API."," Sekrety zostają w aplikacji, a serwer ma te same limity co przeglądarka, czyli 5 quizów na godzinę z jednego adresu IP.",[1186,1699,1700,1703],{},[1189,1701,1702],{},"Narzędzie, które coś kosztuje, wymaga zgody."," Opis narzędzia, adnotacje i skill mówią to samo: najpierw argumenty, potem potwierdzenie. Nie wyłączaj potwierdzeń dla wszystkich narzędzi naraz.",[1186,1705,1706,1709,1710,1713],{},[1189,1707,1708],{},"Zaczynaj od odczytu."," W kursie drugie narzędzie, ",[25,1711,1712],{},"get-leaderboard",", dopisujesz samodzielnie w zadaniu. To narzędzie tylko odczytuje ranking quizu, więc agent może z niego korzystać bez kosztów i bez zmian w danych.",[14,1715,1717],{"id":1716},"najczęstsze-pytania","Najczęstsze pytania",[1308,1719,1721],{"id":1720},"czy-serwer-mcp-musi-być-publicznie-dostępny","Czy serwer MCP musi być publicznie dostępny?",[10,1723,1724],{},"Nie. Serwer stdio działa lokalnie jako proces uruchamiany przez agenta. Publiczny adres jest potrzebny dopiero wtedy, gdy z serwera mają korzystać ChatGPT albo claude.ai. W kursie taki zdalny serwer udostępnia tylko ranking, czyli odczyt bez kosztów, więc działa bez logowania. Płatne tworzenie quizu zostaje w serwerze lokalnym, bo zdalnie wymagałoby logowania i ochrony przed kosztami.",[1308,1726,1728],{"id":1727},"kiedy-wystarczy-skill-a-kiedy-potrzebny-jest-serwer-mcp","Kiedy wystarczy skill, a kiedy potrzebny jest serwer MCP?",[10,1730,1731],{},"Skill to instrukcja dla agenta. Mówi, kiedy i jak wykonać zadanie, ale niczego nie wywołuje w aplikacji. Serwer MCP daje agentowi narzędzie, które coś robi, na przykład tworzy quiz. Do pilnowania zasad projektu wystarczy skill. Do zmian w danych aplikacji potrzebny jest serwer MCP, a skill podpowiada agentowi, kiedy z niego skorzystać.",[1308,1733,1735],{"id":1734},"czy-do-nauki-potrzebny-jest-płatny-agent","Czy do nauki potrzebny jest płatny agent?",[10,1737,1738],{},"Nie. MCP Inspector jest darmowy i wystarcza do sprawdzenia narzędzi. Claude Code wymaga płatnego planu Claude albo konta API z płatnością za użycie, a dostęp do Codex i Copilot zależy od ich aktualnych planów.",[10,1740,1741,1742,32],{},"Serwer z tego wpisu piszemy w Kursie 4 DevChallenge. Najpierw powstaje narzędzie i testy protokołu, potem łączymy je z Claude Code, Codex i Copilot, razem ze skillem projektu, automatyczną oceną jakości quizów i rankingiem w okienku czatu. Wszystkie lekcje znajdziesz w ",[1681,1743,1745],{"href":1744},"\u002Fkursy\u002Fprogram#part-4","programie kursu",[1747,1748,1749],"style",{},"html pre.shiki code .seHd6,html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sn6KH,html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sVyAn,html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .subq3,html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sU0A5,html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sjrmR,html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sVbv2,html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .s_ZVi,html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sVC51,html code.shiki .sVC51{--shiki-default:#D19A66}html .default .shiki span{color:var(--shiki-default);background:var(--shiki-default-bg);font-style:var(--shiki-default-font-style);font-weight:var(--shiki-default-font-weight);text-decoration:var(--shiki-default-text-decoration)}html .shiki span{color:var(--shiki-default);background:var(--shiki-default-bg);font-style:var(--shiki-default-font-style);font-weight:var(--shiki-default-font-weight);text-decoration:var(--shiki-default-text-decoration)}",{"title":53,"searchDepth":102,"depth":102,"links":1751},[1752,1754,1756,1758,1766,1768,1770,1772],{"id":16,"depth":85,"text":1753},"Co to jest serwer MCP i jak działa",{"id":38,"depth":85,"text":1755},"Narzędzie MCP w TypeScript",{"id":1235,"depth":85,"text":1757},"Najpierw sprawdź serwer w MCP Inspector",{"id":1302,"depth":85,"text":1759,"children":1760},"Ten sam serwer w Claude Code, Codex i Copilot",[1761,1763,1764],{"id":1310,"depth":102,"text":1762},"Claude Code",{"id":1397,"depth":102,"text":1398},{"id":1450,"depth":102,"text":1765},"Copilot w VS Code",{"id":1565,"depth":85,"text":1767},"Skill w Claude Code i Codex: kiedy agent ma zapytać o zgodę",{"id":1669,"depth":85,"text":1769},"Co agent naprawdę robi z Twoim kodem",{"id":1687,"depth":85,"text":1771},"Bezpieczeństwo serwera MCP w trzech zasadach",{"id":1716,"depth":85,"text":1717,"children":1773},[1774,1776,1778],{"id":1720,"depth":102,"text":1775},"Czy serwer MCP musi być publicznie dostępny?",{"id":1727,"depth":102,"text":1777},"Kiedy wystarczy skill, a kiedy potrzebny jest serwer MCP?",{"id":1734,"depth":102,"text":1779},"Czy do nauki potrzebny jest płatny agent?","AI w praktyce",null,"2026-08-30","Serwer MCP w TypeScript: narzędzie z Zod, test w MCP Inspector i ten sam serwer w Claude Code, Codex i Copilot w VS Code.","md",{},"\u002Fblog\u002Fprogramowanie\u002Fserwer-mcp-typescript","10 min",{"title":5,"description":1783},{"loc":1786},"blog\u002Fprogramowanie\u002Fserwer-mcp-typescript","2026-11-01","GBg9yCosG1sjUB5PZZz3CPL1NGMJ0McYC5ByLfsfNpY",[1794,1798,1803,1809,1814,1820,1825],{"title":1795,"path":1683,"description":1796,"category":1780,"date":1797},"RAG vs MCP na przykładzie jednej aplikacji","RAG czy MCP? Na przykładzie aplikacji z quizami pokazuję, kiedy model potrzebuje wiedzy z Twojego PDF-a, a kiedy narzędzia, które coś zrobi w aplikacji.","2026-08-23",{"title":1799,"path":1800,"description":1801,"category":1780,"date":1802},"Automatyzacja z AI w 6 poziomach: od skryptu po agenta","\u002Fblog\u002Fprogramowanie\u002Fjak-zautomatyzowac-prace","Jak zautomatyzować pracę z AI? Porównaj skrypt, RPA, n8n, czat z AI i agentów na raporcie z arkusza, który co tydzień wysyłasz mailem przełożonemu.","2026-08-16",{"title":1804,"path":1805,"description":1806,"category":1807,"date":1808},"Jak nauczyć się matematyki bez wkuwania wzorów","\u002Fblog\u002Fmatematyka\u002Fjak-nauczyc-sie-matematyki","Jak nauczyć się matematyki bez wkuwania wzorów? Sprawdź, jak znaleźć braki w podstawach, ćwiczyć samodzielnie i po kolei nadrobić zaległości.","Matematyka","2026-08-12",{"title":1810,"path":1811,"description":1812,"category":1780,"date":1813},"Jak zostać Full Stack Developerem w erze AI? 8 kroków","\u002Fblog\u002Fprogramowanie\u002Ffullstack-developer-w-dobie-ai","Jak zostać Full Stack Developerem? Plan nauki od HTML i JavaScriptu po backend, bazę danych i wdrożenie. Zobacz, jak korzystać z AI podczas nauki.","2026-08-09",{"title":1815,"path":1816,"description":1817,"category":1818,"date":1819},"Jak myśleć jak programista? Najpierw problem, potem kod","\u002Fblog\u002Fprogramowanie\u002Fjak-myslec-jak-programista","Jak myśleć jak programista? Zobacz, jak podzielić problem na kroki, napisać pseudokod i sprawdzić plan, zanim przełożysz go na JavaScript.","Programowanie","2026-08-02",{"title":1821,"path":1822,"description":1823,"category":1818,"date":1824},"Jak zacząć programować od zera? Plan na pierwsze 8 tygodni","\u002Fblog\u002Fprogramowanie\u002Fjak-zaczac-programowac-od-zera","Jak zacząć programować od zera? Wybierz język pod swój cel, przejdź 8-tygodniowy plan i zbuduj pierwszy projekt bez skakania między kursami.","2026-07-26",{"title":1826,"path":1827,"description":1828,"category":1807,"date":1829},"Jak zaplanować naukę do matury z matematyki","\u002Fblog\u002Fmatematyka\u002Fprzygotowanie-do-matury-z-matematyki","Jak przygotować się do matury z matematyki? Zacznij od arkusza CKE, powtarzaj po jednym dziale i ułóż tydzień nauki, który da Ci zapas ponad próg 30%.","2026-07-22",1794052151313]