From e7431e902458012199ee37dd60b921c3e9a817a9 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 20:29:55 +0200 Subject: [PATCH 01/30] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e167ec5..ede829f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Repo for the official Svelte MCP server. ``` pnpm i -cp .env.example .env +cp apps/mcp-remote/.env.example apps/mcp-remote/.env pnpm dev ``` From 972cadc410cdcbcfcf1ce3c222e565b0a8c7de16 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 20:30:16 +0200 Subject: [PATCH 02/30] Update package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 5e5b67e..e2557b3 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "build": "pnpm -r run build", + "dev": "pnpm --filter @sveltejs/mcp-remote run dev", "check": "pnpm -r run check", "format": "prettier --write .", "lint": "prettier --check . && eslint .", From 917fdf63b1ab2f612401732eb3352539d37b653e Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 20:34:57 +0200 Subject: [PATCH 03/30] enable --- packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts | 2 +- packages/mcp-server/src/mcp/handlers/tools/list-sections.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 6b3ddf0..51951c0 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -5,7 +5,7 @@ export function get_documentation(server: SvelteMcp) { server.tool( { name: 'get-documentation', - enabled: () => false, + enabled: () => true, description: 'Retrieves full documentation content for Svelte 5 or SvelteKit sections. Supports flexible search by title (e.g., "$state", "routing") or file path (e.g., "docs/svelte/state.md"). Can accept a single section name or an array of sections. Before running this, make sure to analyze the users query, as well as the output from list_sections (which should be called first). Then ask for ALL relevant sections the user might require. For example, if the user asks to build anything interactive, you will need to fetch all relevant runes, and so on.', schema: v.object({ diff --git a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts index 6d35a63..5fa661b 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts @@ -4,7 +4,7 @@ export function list_sections(server: SvelteMcp) { server.tool( { name: 'list-sections', - enabled: () => false, + enabled: () => true, description: 'Lists all available Svelte 5 and SvelteKit documentation sections in a structured format. Returns sections as a list of "* title: [section_title], path: [file_path]" - you can use either the title or path when querying a specific section via the get_documentation tool. Always run list_sections first for any query related to Svelte development to discover available content.', }, From 68cf69a117ffa6fe350689456d2d4fd477132814 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 20:38:17 +0200 Subject: [PATCH 04/30] wip --- .../src/mcp/handlers/tools/list-sections.ts | 8 +++++++- packages/mcp-server/src/mcp/utils.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 packages/mcp-server/src/mcp/utils.ts diff --git a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts index 5fa661b..7d9f19b 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts @@ -1,4 +1,5 @@ import type { SvelteMcp } from '../../index.js'; +import { getSections } from '../../utils.js'; export function list_sections(server: SvelteMcp) { server.tool( @@ -9,11 +10,16 @@ export function list_sections(server: SvelteMcp) { 'Lists all available Svelte 5 and SvelteKit documentation sections in a structured format. Returns sections as a list of "* title: [section_title], path: [file_path]" - you can use either the title or path when querying a specific section via the get_documentation tool. Always run list_sections first for any query related to Svelte development to discover available content.', }, () => { + const sections = getSections(); + const formattedSections = sections + .map(section => `* title: ${section.title}, path: ${section.url}`) + .join('\n'); + return { content: [ { type: 'text', - text: 'tool list_sections called', + text: formattedSections, }, ], }; diff --git a/packages/mcp-server/src/mcp/utils.ts b/packages/mcp-server/src/mcp/utils.ts new file mode 100644 index 0000000..9358df3 --- /dev/null +++ b/packages/mcp-server/src/mcp/utils.ts @@ -0,0 +1,19 @@ +export function getSections() { + return [ + { + title: 'Overview', + url: 'https://svelte.dev/docs/svelte/overview/llms.txt', + description: 'Useful when a beginner learns about Svelte', + }, + { + title: 'Getting Started', + url: 'https://svelte.dev/docs/svelte/getting-started/llms.txt', + description: 'Useful when a beginner is starting a new Svelte project', + }, + { + title: 'Svelte Files', + url: 'https://svelte.dev/docs/svelte/svelte-files/llms.txt', + description: 'Useful when a beginner is learning about Svelte files', + }, + ]; +} From 19cacf7ed936e2468393786d2eecfff38aa1c801 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 20:39:22 +0200 Subject: [PATCH 05/30] refactor --- .../mcp-server/src/mcp/handlers/tools/list-sections.ts | 4 ++-- packages/mcp-server/src/mcp/utils.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts index 7d9f19b..514cf0f 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts @@ -9,8 +9,8 @@ export function list_sections(server: SvelteMcp) { description: 'Lists all available Svelte 5 and SvelteKit documentation sections in a structured format. Returns sections as a list of "* title: [section_title], path: [file_path]" - you can use either the title or path when querying a specific section via the get_documentation tool. Always run list_sections first for any query related to Svelte development to discover available content.', }, - () => { - const sections = getSections(); + async () => { + const sections = await getSections(); const formattedSections = sections .map(section => `* title: ${section.title}, path: ${section.url}`) .join('\n'); diff --git a/packages/mcp-server/src/mcp/utils.ts b/packages/mcp-server/src/mcp/utils.ts index 9358df3..3038fb3 100644 --- a/packages/mcp-server/src/mcp/utils.ts +++ b/packages/mcp-server/src/mcp/utils.ts @@ -1,19 +1,19 @@ -export function getSections() { +export async function getSections() { return [ { title: 'Overview', url: 'https://svelte.dev/docs/svelte/overview/llms.txt', - description: 'Useful when a beginner learns about Svelte', + use_cases: 'Useful when a beginner learns about Svelte', }, { title: 'Getting Started', url: 'https://svelte.dev/docs/svelte/getting-started/llms.txt', - description: 'Useful when a beginner is starting a new Svelte project', + use_cases: 'Useful when a beginner is starting a new Svelte project', }, { title: 'Svelte Files', url: 'https://svelte.dev/docs/svelte/svelte-files/llms.txt', - description: 'Useful when a beginner is learning about Svelte files', + use_cases: 'Useful when a beginner is learning about Svelte files', }, ]; } From e314ab57b2d3368e210bd563d11552d9b8e2fb63 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 20:43:04 +0200 Subject: [PATCH 06/30] Update list-sections.ts --- .../src/mcp/handlers/tools/list-sections.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts index 514cf0f..7ab08ff 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts @@ -12,14 +12,22 @@ export function list_sections(server: SvelteMcp) { async () => { const sections = await getSections(); const formattedSections = sections - .map(section => `* title: ${section.title}, path: ${section.url}`) + .map( + (section) => + `* title: ${section.title}, use cases: ${section.use_cases}, path: ${section.url}`, + ) .join('\n'); + const introText = 'List of available Svelte documentation sections and its inteneded uses:'; + + const outroText = + 'Use the title or path with the get-documentation tool to get more details about a specific section.'; + return { content: [ { type: 'text', - text: formattedSections, + text: `${introText}\n\n${formattedSections}\n\n${outroText}`, }, ], }; From 1bb171cea79090a312f3ebe08075e1672e6b2e2a Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 20:44:41 +0200 Subject: [PATCH 07/30] cleanup --- CLAUDE.md | 6 +++--- .../mcp-server/src/mcp/handlers/tools/get-documentation.ts | 2 +- packages/mcp-server/src/mcp/handlers/tools/list-sections.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c240871..855c15c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,12 +90,12 @@ When connected to the svelte-llm MCP server, you have access to comprehensive Sv ## Available MCP Tools: -### 1. list_sections +### 1. list-sections Use this FIRST to discover all available documentation sections. Returns a structured list with titles and paths. When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections. -### 2. get_documentation +### 2. get-documentation Retrieves full documentation content for specific sections. Accepts single or multiple sections. -After calling the list_sections tool, you MUST analyze the returned documentation sections and then use the get_documentation tool to fetch ALL documentation sections that are relevant for the users task. +After calling the list-sections tool, you MUST analyze the returned documentation sections and then use the get_documentation tool to fetch ALL documentation sections that are relevant for the users task. diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 51951c0..ec4b044 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -7,7 +7,7 @@ export function get_documentation(server: SvelteMcp) { name: 'get-documentation', enabled: () => true, description: - 'Retrieves full documentation content for Svelte 5 or SvelteKit sections. Supports flexible search by title (e.g., "$state", "routing") or file path (e.g., "docs/svelte/state.md"). Can accept a single section name or an array of sections. Before running this, make sure to analyze the users query, as well as the output from list_sections (which should be called first). Then ask for ALL relevant sections the user might require. For example, if the user asks to build anything interactive, you will need to fetch all relevant runes, and so on.', + 'Retrieves full documentation content for Svelte 5 or SvelteKit sections. Supports flexible search by title (e.g., "$state", "routing") or file path (e.g., "docs/svelte/state.md"). Can accept a single section name or an array of sections. Before running this, make sure to analyze the users query, as well as the output from list-sections (which should be called first). Then ask for ALL relevant sections the user might require. For example, if the user asks to build anything interactive, you will need to fetch all relevant runes, and so on.', schema: v.object({ section: v.pipe( v.union([v.string(), v.array(v.string())]), diff --git a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts index 7ab08ff..fe4815a 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts @@ -7,14 +7,14 @@ export function list_sections(server: SvelteMcp) { name: 'list-sections', enabled: () => true, description: - 'Lists all available Svelte 5 and SvelteKit documentation sections in a structured format. Returns sections as a list of "* title: [section_title], path: [file_path]" - you can use either the title or path when querying a specific section via the get_documentation tool. Always run list_sections first for any query related to Svelte development to discover available content.', + 'Lists all available Svelte 5 and SvelteKit documentation sections in a structured format. Returns sections as a list of "* title: [section_title], use_cases: [use_cases], path: [file_path]" - you can use either the title or path when querying a specific section via the get_documentation tool. Always run list-sections first for any query related to Svelte development to discover available content.', }, async () => { const sections = await getSections(); const formattedSections = sections .map( (section) => - `* title: ${section.title}, use cases: ${section.use_cases}, path: ${section.url}`, + `* title: ${section.title}, use_cases: ${section.use_cases}, path: ${section.url}`, ) .join('\n'); From d33a374417d36fda8644827127b08a6d5e1762af Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 21:56:38 +0200 Subject: [PATCH 08/30] Update get-documentation.ts --- .../mcp/handlers/tools/get-documentation.ts | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index ec4b044..49e3852 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -1,5 +1,6 @@ import type { SvelteMcp } from '../../index.js'; import * as v from 'valibot'; +import { getSections } from '../../utils.js'; export function get_documentation(server: SvelteMcp) { server.tool( @@ -17,7 +18,7 @@ export function get_documentation(server: SvelteMcp) { ), }), }, - ({ section }) => { + async ({ section }) => { let sections: string[]; if (Array.isArray(section)) { @@ -43,13 +44,37 @@ export function get_documentation(server: SvelteMcp) { sections = []; } - const sections_list = sections.length > 0 ? sections.join(', ') : 'no sections'; + const availableSections = await getSections(); + const results: string[] = []; + + for (const requestedSection of sections) { + const matchedSection = availableSections.find( + s => s.title.toLowerCase() === requestedSection.toLowerCase() || + s.url === requestedSection + ); + + if (matchedSection) { + try { + const response = await fetch(matchedSection.url); + if (response.ok) { + const content = await response.text(); + results.push(`## ${matchedSection.title}\n\n${content}`); + } else { + results.push(`## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})`); + } + } catch (error) { + results.push(`## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}`); + } + } else { + results.push(`## ${requestedSection}\n\nError: Section not found. Available sections: ${availableSections.map(s => s.title).join(', ')}`); + } + } return { content: [ { type: 'text', - text: `called for sections: ${sections_list}`, + text: results.join('\n\n---\n\n'), }, ], }; From 6cb97ac11d5bce9754c90ac4f37b05275921cf99 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 22:36:30 +0200 Subject: [PATCH 09/30] Update get-documentation.ts --- .../mcp/handlers/tools/get-documentation.ts | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 49e3852..9116604 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -45,30 +45,31 @@ export function get_documentation(server: SvelteMcp) { } const availableSections = await getSections(); - const results: string[] = []; - for (const requestedSection of sections) { - const matchedSection = availableSections.find( - s => s.title.toLowerCase() === requestedSection.toLowerCase() || - s.url === requestedSection - ); + const results = await Promise.all( + sections.map(async (requestedSection) => { + const matchedSection = availableSections.find( + s => s.title.toLowerCase() === requestedSection.toLowerCase() || + s.url === requestedSection + ); - if (matchedSection) { - try { - const response = await fetch(matchedSection.url); - if (response.ok) { - const content = await response.text(); - results.push(`## ${matchedSection.title}\n\n${content}`); - } else { - results.push(`## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})`); + if (matchedSection) { + try { + const response = await fetch(matchedSection.url); + if (response.ok) { + const content = await response.text(); + return `## ${matchedSection.title}\n\n${content}`; + } else { + return `## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})`; + } + } catch (error) { + return `## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}`; } - } catch (error) { - results.push(`## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}`); + } else { + return `## ${requestedSection}\n\nError: Section not found. Available sections: ${availableSections.map(s => s.title).join(', ')}`; } - } else { - results.push(`## ${requestedSection}\n\nError: Section not found. Available sections: ${availableSections.map(s => s.title).join(', ')}`); - } - } + }) + ); return { content: [ From c49b24d36a3c83b7a451ac51e352c671d2322434 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 22:39:52 +0200 Subject: [PATCH 10/30] wip --- .../src/mcp/handlers/tools/get-documentation.ts | 4 ++-- packages/mcp-server/src/mcp/utils.ts | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 9116604..2a90e98 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -1,6 +1,6 @@ import type { SvelteMcp } from '../../index.js'; import * as v from 'valibot'; -import { getSections } from '../../utils.js'; +import { getSections, fetchWithTimeout } from '../../utils.js'; export function get_documentation(server: SvelteMcp) { server.tool( @@ -55,7 +55,7 @@ export function get_documentation(server: SvelteMcp) { if (matchedSection) { try { - const response = await fetch(matchedSection.url); + const response = await fetchWithTimeout(matchedSection.url); if (response.ok) { const content = await response.text(); return `## ${matchedSection.title}\n\n${content}`; diff --git a/packages/mcp-server/src/mcp/utils.ts b/packages/mcp-server/src/mcp/utils.ts index 3038fb3..a89135c 100644 --- a/packages/mcp-server/src/mcp/utils.ts +++ b/packages/mcp-server/src/mcp/utils.ts @@ -1,3 +1,20 @@ +export async function fetchWithTimeout(url: string, timeoutMs: number = 10000): Promise { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + try { + const response = await fetch(url, { signal: controller.signal }); + clearTimeout(timeoutId); + return response; + } catch (error) { + clearTimeout(timeoutId); + if (error instanceof Error && error.name === 'AbortError') { + throw new Error(`Request timed out after ${timeoutMs}ms`); + } + throw error; + } +} + export async function getSections() { return [ { From b774b463fea02fb17c9289c46a839567158c4fd2 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 22:42:42 +0200 Subject: [PATCH 11/30] Update get-documentation.ts --- .../src/mcp/handlers/tools/get-documentation.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 2a90e98..4cc93e0 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -66,7 +66,19 @@ export function get_documentation(server: SvelteMcp) { return `## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}`; } } else { - return `## ${requestedSection}\n\nError: Section not found. Available sections: ${availableSections.map(s => s.title).join(', ')}`; + const formattedSections = availableSections + .map( + (section) => + `* title: ${section.title}, use_cases: ${section.use_cases}, path: ${section.url}`, + ) + .join('\n'); + + const introText = 'List of available Svelte documentation sections and its inteneded uses:'; + + const outroText = + 'Use the title or path with the get-documentation tool to get more details about a specific section.'; + + return `## ${requestedSection}\n\nError: Section not found.\n\n${introText}\n\n${formattedSections}\n\n${outroText}`; } }) ); From 0f5482477a2ad244a145cc6df2fe9d1818efb642 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 22:44:28 +0200 Subject: [PATCH 12/30] Update get-documentation.ts --- .../mcp/handlers/tools/get-documentation.ts | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 4cc93e0..64e598f 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -58,36 +58,43 @@ export function get_documentation(server: SvelteMcp) { const response = await fetchWithTimeout(matchedSection.url); if (response.ok) { const content = await response.text(); - return `## ${matchedSection.title}\n\n${content}`; + return { success: true, content: `## ${matchedSection.title}\n\n${content}` }; } else { - return `## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})`; + return { success: false, content: `## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})` }; } } catch (error) { - return `## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}`; + return { success: false, content: `## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}` }; } } else { - const formattedSections = availableSections - .map( - (section) => - `* title: ${section.title}, use_cases: ${section.use_cases}, path: ${section.url}`, - ) - .join('\n'); - - const introText = 'List of available Svelte documentation sections and its inteneded uses:'; - - const outroText = - 'Use the title or path with the get-documentation tool to get more details about a specific section.'; - - return `## ${requestedSection}\n\nError: Section not found.\n\n${introText}\n\n${formattedSections}\n\n${outroText}`; + return { success: false, content: `## ${requestedSection}\n\nError: Section not found.` }; } }) ); + const hasAnySuccess = results.some(result => result.success); + let finalText = results.map(r => r.content).join('\n\n---\n\n'); + + if (!hasAnySuccess) { + const formattedSections = availableSections + .map( + (section) => + `* title: ${section.title}, use_cases: ${section.use_cases}, path: ${section.url}`, + ) + .join('\n'); + + const introText = 'List of available Svelte documentation sections and its inteneded uses:'; + + const outroText = + 'Use the title or path with the get-documentation tool to get more details about a specific section.'; + + finalText += `\n\n---\n\n${introText}\n\n${formattedSections}\n\n${outroText}`; + } + return { content: [ { type: 'text', - text: results.join('\n\n---\n\n'), + text: finalText, }, ], }; From bf477a6ccfb433e5bc6c62ad1c7697d53c48d3b0 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 23:46:07 +0200 Subject: [PATCH 13/30] Update get-documentation.ts --- .../mcp/handlers/tools/get-documentation.ts | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 64e598f..e4a8e77 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -49,8 +49,9 @@ export function get_documentation(server: SvelteMcp) { const results = await Promise.all( sections.map(async (requestedSection) => { const matchedSection = availableSections.find( - s => s.title.toLowerCase() === requestedSection.toLowerCase() || - s.url === requestedSection + (s) => + s.title.toLowerCase() === requestedSection.toLowerCase() || + s.url === requestedSection, ); if (matchedSection) { @@ -60,19 +61,28 @@ export function get_documentation(server: SvelteMcp) { const content = await response.text(); return { success: true, content: `## ${matchedSection.title}\n\n${content}` }; } else { - return { success: false, content: `## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})` }; + return { + success: false, + content: `## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})`, + }; } } catch (error) { - return { success: false, content: `## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}` }; + return { + success: false, + content: `## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}`, + }; } } else { - return { success: false, content: `## ${requestedSection}\n\nError: Section not found.` }; + return { + success: false, + content: `## ${requestedSection}\n\nError: Section not found.`, + }; } - }) + }), ); - const hasAnySuccess = results.some(result => result.success); - let finalText = results.map(r => r.content).join('\n\n---\n\n'); + const hasAnySuccess = results.some((result) => result.success); + let finalText = results.map((r) => r.content).join('\n\n---\n\n'); if (!hasAnySuccess) { const formattedSections = availableSections From 7f9ea742d8fceb3bad4223511877c506fcea5323 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 23:48:15 +0200 Subject: [PATCH 14/30] don't lint .claude dir --- .prettierignore | 5 ++++- eslint.config.js | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 611d858..b6c8873 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,4 +8,7 @@ bun.lockb # Miscellaneous /static/ /drizzle/ -/**/.svelte-kit/* \ No newline at end of file +/**/.svelte-kit/* + +# Claude Code +.claude/ \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js index 2552bfd..325387f 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -12,6 +12,9 @@ const gitignore_path = fileURLToPath(new URL('./.gitignore', import.meta.url)); export default /** @type {import("eslint").Linter.Config} */ ([ includeIgnoreFile(gitignore_path), + { + ignores: ['.claude/**/*'], + }, js.configs.recommended, ...ts.configs.recommended, ...svelte.configs.recommended, From c05b6c257ad1b8e8c34c7075069227d06b252660 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 23:51:48 +0200 Subject: [PATCH 15/30] eslint --- .../src/mcp/handlers/tools/list-sections.ts | 12 ++++++------ packages/mcp-server/src/mcp/utils.ts | 15 +++++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts index fe4815a..a9ff575 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts @@ -1,5 +1,5 @@ import type { SvelteMcp } from '../../index.js'; -import { getSections } from '../../utils.js'; +import { get_sections } from '../../utils.js'; export function list_sections(server: SvelteMcp) { server.tool( @@ -10,24 +10,24 @@ export function list_sections(server: SvelteMcp) { 'Lists all available Svelte 5 and SvelteKit documentation sections in a structured format. Returns sections as a list of "* title: [section_title], use_cases: [use_cases], path: [file_path]" - you can use either the title or path when querying a specific section via the get_documentation tool. Always run list-sections first for any query related to Svelte development to discover available content.', }, async () => { - const sections = await getSections(); - const formattedSections = sections + const sections = await get_sections(); + const formatted_sections = sections .map( (section) => `* title: ${section.title}, use_cases: ${section.use_cases}, path: ${section.url}`, ) .join('\n'); - const introText = 'List of available Svelte documentation sections and its inteneded uses:'; + const intro_text = 'List of available Svelte documentation sections and its inteneded uses:'; - const outroText = + const outro_text = 'Use the title or path with the get-documentation tool to get more details about a specific section.'; return { content: [ { type: 'text', - text: `${introText}\n\n${formattedSections}\n\n${outroText}`, + text: `${intro_text}\n\n${formatted_sections}\n\n${outro_text}`, }, ], }; diff --git a/packages/mcp-server/src/mcp/utils.ts b/packages/mcp-server/src/mcp/utils.ts index a89135c..76543e0 100644 --- a/packages/mcp-server/src/mcp/utils.ts +++ b/packages/mcp-server/src/mcp/utils.ts @@ -1,21 +1,24 @@ -export async function fetchWithTimeout(url: string, timeoutMs: number = 10000): Promise { +export async function fetch_with_timeout( + url: string, + timeout_ms: number = 10000, +): Promise { const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + const timeout_id = setTimeout(() => controller.abort(), timeout_ms); try { const response = await fetch(url, { signal: controller.signal }); - clearTimeout(timeoutId); + clearTimeout(timeout_id); return response; } catch (error) { - clearTimeout(timeoutId); + clearTimeout(timeout_id); if (error instanceof Error && error.name === 'AbortError') { - throw new Error(`Request timed out after ${timeoutMs}ms`); + throw new Error(`Request timed out after ${timeout_ms}ms`); } throw error; } } -export async function getSections() { +export async function get_sections() { return [ { title: 'Overview', From 8328a3572b45bb9ad871054186c8d2fe86f373d4 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 23:51:58 +0200 Subject: [PATCH 16/30] eslint --- .../mcp/handlers/tools/get-documentation.ts | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index e4a8e77..334b63a 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -1,6 +1,6 @@ import type { SvelteMcp } from '../../index.js'; import * as v from 'valibot'; -import { getSections, fetchWithTimeout } from '../../utils.js'; +import { get_sections, fetch_with_timeout } from '../../utils.js'; export function get_documentation(server: SvelteMcp) { server.tool( @@ -44,67 +44,68 @@ export function get_documentation(server: SvelteMcp) { sections = []; } - const availableSections = await getSections(); + const available_sections = await get_sections(); const results = await Promise.all( - sections.map(async (requestedSection) => { - const matchedSection = availableSections.find( + sections.map(async (requested_section) => { + const matched_section = available_sections.find( (s) => - s.title.toLowerCase() === requestedSection.toLowerCase() || - s.url === requestedSection, + s.title.toLowerCase() === requested_section.toLowerCase() || + s.url === requested_section, ); - if (matchedSection) { + if (matched_section) { try { - const response = await fetchWithTimeout(matchedSection.url); + const response = await fetch_with_timeout(matched_section.url); if (response.ok) { const content = await response.text(); - return { success: true, content: `## ${matchedSection.title}\n\n${content}` }; + return { success: true, content: `## ${matched_section.title}\n\n${content}` }; } else { return { success: false, - content: `## ${matchedSection.title}\n\nError: Could not fetch documentation (HTTP ${response.status})`, + content: `## ${matched_section.title}\n\nError: Could not fetch documentation (HTTP ${response.status})`, }; } } catch (error) { return { success: false, - content: `## ${matchedSection.title}\n\nError: Failed to fetch documentation - ${error}`, + content: `## ${matched_section.title}\n\nError: Failed to fetch documentation - ${error}`, }; } } else { return { success: false, - content: `## ${requestedSection}\n\nError: Section not found.`, + content: `## ${requested_section}\n\nError: Section not found.`, }; } }), ); - const hasAnySuccess = results.some((result) => result.success); - let finalText = results.map((r) => r.content).join('\n\n---\n\n'); + const has_any_success = results.some((result) => result.success); + let final_text = results.map((r) => r.content).join('\n\n---\n\n'); - if (!hasAnySuccess) { - const formattedSections = availableSections + if (!has_any_success) { + const formatted_sections = available_sections .map( (section) => `* title: ${section.title}, use_cases: ${section.use_cases}, path: ${section.url}`, ) .join('\n'); - const introText = 'List of available Svelte documentation sections and its inteneded uses:'; + const intro_text = + 'List of available Svelte documentation sections and its inteneded uses:'; - const outroText = + const outro_text = 'Use the title or path with the get-documentation tool to get more details about a specific section.'; - finalText += `\n\n---\n\n${introText}\n\n${formattedSections}\n\n${outroText}`; + final_text += `\n\n---\n\n${intro_text}\n\n${formatted_sections}\n\n${outro_text}`; } return { content: [ { type: 'text', - text: finalText, + text: final_text, }, ], }; From fb2d19fd077bffd07c3119d7d69348c992122d21 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Fri, 26 Sep 2025 23:59:18 +0200 Subject: [PATCH 17/30] Update list-sections.ts --- .../mcp/handlers/resources/list-sections.ts | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts b/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts index c36e8e3..6c9ca00 100644 --- a/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts @@ -1,25 +1,34 @@ import type { SvelteMcp } from '../../index.js'; +import { get_sections, fetch_with_timeout } from '../../utils.js'; -export function list_sections(server: SvelteMcp) { - server.resource( - { - name: 'list-sections', - enabled: () => false, - description: - 'The list of all the available Svelte 5 and SvelteKit documentation sections in a structured format.', - uri: 'svelte://list-sections', - title: 'Svelte Documentation Section', - }, - async (uri) => { - return { - contents: [ - { - uri, - type: 'text', - text: 'resource list-sections called', - }, - ], - }; - }, - ); +export async function list_sections(server: SvelteMcp) { + const sections = await get_sections(); + + sections.forEach((section) => { + const resource_name = section.title.toLowerCase().replace(/\s+/g, '-'); + const resource_uri = `svelte://docs/${resource_name}`; + + server.resource( + { + name: resource_name, + enabled: () => true, + description: section.use_cases, + uri: resource_uri, + title: section.title, + }, + async (uri) => { + const response = await fetch_with_timeout(section.url); + const content = await response.text(); + return { + contents: [ + { + uri, + type: 'text', + text: content, + }, + ], + }; + }, + ); + }); } From b1a196497daff8c84a03ef4a6761f9fb3af48f17 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Sat, 27 Sep 2025 00:00:15 +0200 Subject: [PATCH 18/30] Update list-sections.ts --- .../mcp-server/src/mcp/handlers/resources/list-sections.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts b/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts index 6c9ca00..fe189af 100644 --- a/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/resources/list-sections.ts @@ -5,8 +5,9 @@ export async function list_sections(server: SvelteMcp) { const sections = await get_sections(); sections.forEach((section) => { - const resource_name = section.title.toLowerCase().replace(/\s+/g, '-'); - const resource_uri = `svelte://docs/${resource_name}`; + const section_name = section.title.toLowerCase().replace(/\s+/g, '-'); + const resource_name = `docs/svelte/${section_name}`; + const resource_uri = `svelte://docs/${section_name}`; server.resource( { From 77af7ebcc6c3c9209365759e4fdfb9d6aadb1ccf Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Sat, 27 Sep 2025 00:01:50 +0200 Subject: [PATCH 19/30] Update packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts Co-authored-by: Paolo Ricciuti --- packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 334b63a..0bbd823 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -6,7 +6,6 @@ export function get_documentation(server: SvelteMcp) { server.tool( { name: 'get-documentation', - enabled: () => true, description: 'Retrieves full documentation content for Svelte 5 or SvelteKit sections. Supports flexible search by title (e.g., "$state", "routing") or file path (e.g., "docs/svelte/state.md"). Can accept a single section name or an array of sections. Before running this, make sure to analyze the users query, as well as the output from list-sections (which should be called first). Then ask for ALL relevant sections the user might require. For example, if the user asks to build anything interactive, you will need to fetch all relevant runes, and so on.', schema: v.object({ From 6a6417d3a558445212f748280be8888a419f39f7 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Sat, 27 Sep 2025 00:03:40 +0200 Subject: [PATCH 20/30] Use Promise.allSettled() --- .../src/mcp/handlers/tools/get-documentation.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 334b63a..0958de8 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -46,7 +46,7 @@ export function get_documentation(server: SvelteMcp) { const available_sections = await get_sections(); - const results = await Promise.all( + const settled_results = await Promise.allSettled( sections.map(async (requested_section) => { const matched_section = available_sections.find( (s) => @@ -81,6 +81,17 @@ export function get_documentation(server: SvelteMcp) { }), ); + const results = settled_results.map((result) => { + if (result.status === 'fulfilled') { + return result.value; + } else { + return { + success: false, + content: `Error: Couldn't fetch - ${result.reason}`, + }; + } + }); + const has_any_success = results.some((result) => result.success); let final_text = results.map((r) => r.content).join('\n\n---\n\n'); From 01d5803b5d219c1d418f539dfb864fd063d313c3 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Sat, 27 Sep 2025 00:06:37 +0200 Subject: [PATCH 21/30] reduce duplication --- .../src/mcp/handlers/tools/get-documentation.ts | 9 ++------- .../mcp-server/src/mcp/handlers/tools/list-sections.ts | 8 ++------ packages/mcp-server/src/mcp/handlers/tools/prompts.ts | 4 ++++ 3 files changed, 8 insertions(+), 13 deletions(-) create mode 100644 packages/mcp-server/src/mcp/handlers/tools/prompts.ts diff --git a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts index 86da836..d68bd12 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/get-documentation.ts @@ -1,6 +1,7 @@ import type { SvelteMcp } from '../../index.js'; import * as v from 'valibot'; import { get_sections, fetch_with_timeout } from '../../utils.js'; +import { SECTIONS_LIST_INTRO, SECTIONS_LIST_OUTRO } from './prompts.js'; export function get_documentation(server: SvelteMcp) { server.tool( @@ -102,13 +103,7 @@ export function get_documentation(server: SvelteMcp) { ) .join('\n'); - const intro_text = - 'List of available Svelte documentation sections and its inteneded uses:'; - - const outro_text = - 'Use the title or path with the get-documentation tool to get more details about a specific section.'; - - final_text += `\n\n---\n\n${intro_text}\n\n${formatted_sections}\n\n${outro_text}`; + final_text += `\n\n---\n\n${SECTIONS_LIST_INTRO}\n\n${formatted_sections}\n\n${SECTIONS_LIST_OUTRO}`; } return { diff --git a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts index a9ff575..f6786ca 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/list-sections.ts @@ -1,5 +1,6 @@ import type { SvelteMcp } from '../../index.js'; import { get_sections } from '../../utils.js'; +import { SECTIONS_LIST_INTRO, SECTIONS_LIST_OUTRO } from './prompts.js'; export function list_sections(server: SvelteMcp) { server.tool( @@ -18,16 +19,11 @@ export function list_sections(server: SvelteMcp) { ) .join('\n'); - const intro_text = 'List of available Svelte documentation sections and its inteneded uses:'; - - const outro_text = - 'Use the title or path with the get-documentation tool to get more details about a specific section.'; - return { content: [ { type: 'text', - text: `${intro_text}\n\n${formatted_sections}\n\n${outro_text}`, + text: `${SECTIONS_LIST_INTRO}\n\n${formatted_sections}\n\n${SECTIONS_LIST_OUTRO}`, }, ], }; diff --git a/packages/mcp-server/src/mcp/handlers/tools/prompts.ts b/packages/mcp-server/src/mcp/handlers/tools/prompts.ts new file mode 100644 index 0000000..e096479 --- /dev/null +++ b/packages/mcp-server/src/mcp/handlers/tools/prompts.ts @@ -0,0 +1,4 @@ +export const SECTIONS_LIST_INTRO = 'List of available Svelte documentation sections and its inteneded uses:'; + +export const SECTIONS_LIST_OUTRO = + 'Use the title or path with the get-documentation tool to get more details about a specific section.'; \ No newline at end of file From 54763e0f55293b81fbfaa9561ca422d896997438 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Sat, 27 Sep 2025 00:07:18 +0200 Subject: [PATCH 22/30] Update packages/mcp-server/src/mcp/utils.ts Co-authored-by: Paolo Ricciuti --- packages/mcp-server/src/mcp/utils.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/mcp-server/src/mcp/utils.ts b/packages/mcp-server/src/mcp/utils.ts index 76543e0..218382b 100644 --- a/packages/mcp-server/src/mcp/utils.ts +++ b/packages/mcp-server/src/mcp/utils.ts @@ -2,17 +2,12 @@ export async function fetch_with_timeout( url: string, timeout_ms: number = 10000, ): Promise { - const controller = new AbortController(); - const timeout_id = setTimeout(() => controller.abort(), timeout_ms); - try { - const response = await fetch(url, { signal: controller.signal }); - clearTimeout(timeout_id); + const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) }); return response; } catch (error) { - clearTimeout(timeout_id); if (error instanceof Error && error.name === 'AbortError') { - throw new Error(`Request timed out after ${timeout_ms}ms`); + throw new Error(`Request timed out after ${timeoutMs}ms`); } throw error; } From 76a35f5dc8b5f6514e1a7955c7bc663bc852003c Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Sat, 27 Sep 2025 00:13:37 +0200 Subject: [PATCH 23/30] format --- packages/mcp-server/src/mcp/handlers/tools/prompts.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/mcp/handlers/tools/prompts.ts b/packages/mcp-server/src/mcp/handlers/tools/prompts.ts index e096479..e574058 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/prompts.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/prompts.ts @@ -1,4 +1,5 @@ -export const SECTIONS_LIST_INTRO = 'List of available Svelte documentation sections and its inteneded uses:'; +export const SECTIONS_LIST_INTRO = + 'List of available Svelte documentation sections and its inteneded uses:'; export const SECTIONS_LIST_OUTRO = - 'Use the title or path with the get-documentation tool to get more details about a specific section.'; \ No newline at end of file + 'Use the title or path with the get-documentation tool to get more details about a specific section.'; From 5dd83d151ef4ddec021c93e2aef0bc472f7a23f3 Mon Sep 17 00:00:00 2001 From: Stanislav Khromov Date: Sat, 27 Sep 2025 00:14:00 +0200 Subject: [PATCH 24/30] Update utils.ts --- packages/mcp-server/src/mcp/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/mcp/utils.ts b/packages/mcp-server/src/mcp/utils.ts index 218382b..2634de7 100644 --- a/packages/mcp-server/src/mcp/utils.ts +++ b/packages/mcp-server/src/mcp/utils.ts @@ -3,11 +3,11 @@ export async function fetch_with_timeout( timeout_ms: number = 10000, ): Promise { try { - const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) }); + const response = await fetch(url, { signal: AbortSignal.timeout(timeout_ms) }); return response; } catch (error) { if (error instanceof Error && error.name === 'AbortError') { - throw new Error(`Request timed out after ${timeoutMs}ms`); + throw new Error(`Request timed out after ${timeout_ms}ms`); } throw error; } From ce0861c1cab04f5cfa7f2f4399e6ef043de38df5 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Sun, 28 Sep 2025 12:18:52 +0200 Subject: [PATCH 25/30] chore: use mocked current version of sections --- packages/mcp-server/src/mcp/utils.ts | 862 ++++++++++++++++++++++++++- 1 file changed, 845 insertions(+), 17 deletions(-) diff --git a/packages/mcp-server/src/mcp/utils.ts b/packages/mcp-server/src/mcp/utils.ts index 2634de7..4e07711 100644 --- a/packages/mcp-server/src/mcp/utils.ts +++ b/packages/mcp-server/src/mcp/utils.ts @@ -13,22 +13,850 @@ export async function fetch_with_timeout( } } +// TODO hardcoded for now but we'll fetch this from svelte.dev +const sections = { + 'docs/cli/overview': { + metadata: { title: 'Overview' }, + slug: 'docs/cli/overview', + file: 'docs/cli/10-introduction/10-overview.md', + }, + 'docs/cli/faq': { + metadata: { title: 'Frequently asked questions' }, + slug: 'docs/cli/faq', + file: 'docs/cli/10-introduction/20-faq.md', + }, + 'docs/cli/sv-create': { + metadata: { title: 'sv create' }, + slug: 'docs/cli/sv-create', + file: 'docs/cli/20-commands/10-sv-create.md', + }, + 'docs/cli/sv-add': { + metadata: { title: 'sv add' }, + slug: 'docs/cli/sv-add', + file: 'docs/cli/20-commands/20-sv-add.md', + }, + 'docs/cli/sv-check': { + metadata: { title: 'sv check' }, + slug: 'docs/cli/sv-check', + file: 'docs/cli/20-commands/30-sv-check.md', + }, + 'docs/cli/sv-migrate': { + metadata: { title: 'sv migrate' }, + slug: 'docs/cli/sv-migrate', + file: 'docs/cli/20-commands/40-sv-migrate.md', + }, + 'docs/cli/devtools-json': { + metadata: { title: 'devtools-json' }, + slug: 'docs/cli/devtools-json', + file: 'docs/cli/30-add-ons/03-devtools-json.md', + }, + 'docs/cli/drizzle': { + metadata: { title: 'drizzle' }, + slug: 'docs/cli/drizzle', + file: 'docs/cli/30-add-ons/05-drizzle.md', + }, + 'docs/cli/eslint': { + metadata: { title: 'eslint' }, + slug: 'docs/cli/eslint', + file: 'docs/cli/30-add-ons/10-eslint.md', + }, + 'docs/cli/lucia': { + metadata: { title: 'lucia' }, + slug: 'docs/cli/lucia', + file: 'docs/cli/30-add-ons/15-lucia.md', + }, + 'docs/cli/mdsvex': { + metadata: { title: 'mdsvex' }, + slug: 'docs/cli/mdsvex', + file: 'docs/cli/30-add-ons/20-mdsvex.md', + }, + 'docs/cli/paraglide': { + metadata: { title: 'paraglide' }, + slug: 'docs/cli/paraglide', + file: 'docs/cli/30-add-ons/25-paraglide.md', + }, + 'docs/cli/playwright': { + metadata: { title: 'playwright' }, + slug: 'docs/cli/playwright', + file: 'docs/cli/30-add-ons/30-playwright.md', + }, + 'docs/cli/prettier': { + metadata: { title: 'prettier' }, + slug: 'docs/cli/prettier', + file: 'docs/cli/30-add-ons/35-prettier.md', + }, + 'docs/cli/storybook': { + metadata: { title: 'storybook' }, + slug: 'docs/cli/storybook', + file: 'docs/cli/30-add-ons/40-storybook.md', + }, + 'docs/cli/sveltekit-adapter': { + metadata: { title: 'sveltekit-adapter' }, + slug: 'docs/cli/sveltekit-adapter', + file: 'docs/cli/30-add-ons/45-sveltekit-adapter.md', + }, + 'docs/cli/tailwind': { + metadata: { title: 'tailwindcss' }, + slug: 'docs/cli/tailwind', + file: 'docs/cli/30-add-ons/50-tailwind.md', + }, + 'docs/cli/vitest': { + metadata: { title: 'vitest' }, + slug: 'docs/cli/vitest', + file: 'docs/cli/30-add-ons/55-vitest.md', + }, + 'docs/kit/introduction': { + metadata: { title: 'Introduction' }, + slug: 'docs/kit/introduction', + file: 'docs/kit/10-getting-started/10-introduction.md', + }, + 'docs/kit/creating-a-project': { + metadata: { title: 'Creating a project' }, + slug: 'docs/kit/creating-a-project', + file: 'docs/kit/10-getting-started/20-creating-a-project.md', + }, + 'docs/kit/project-types': { + metadata: { title: 'Project types' }, + slug: 'docs/kit/project-types', + file: 'docs/kit/10-getting-started/25-project-types.md', + }, + 'docs/kit/project-structure': { + metadata: { title: 'Project structure' }, + slug: 'docs/kit/project-structure', + file: 'docs/kit/10-getting-started/30-project-structure.md', + }, + 'docs/kit/web-standards': { + metadata: { title: 'Web standards' }, + slug: 'docs/kit/web-standards', + file: 'docs/kit/10-getting-started/40-web-standards.md', + }, + 'docs/kit/routing': { + metadata: { title: 'Routing' }, + slug: 'docs/kit/routing', + file: 'docs/kit/20-core-concepts/10-routing.md', + }, + 'docs/kit/load': { + metadata: { title: 'Loading data' }, + slug: 'docs/kit/load', + file: 'docs/kit/20-core-concepts/20-load.md', + }, + 'docs/kit/form-actions': { + metadata: { title: 'Form actions' }, + slug: 'docs/kit/form-actions', + file: 'docs/kit/20-core-concepts/30-form-actions.md', + }, + 'docs/kit/page-options': { + metadata: { title: 'Page options' }, + slug: 'docs/kit/page-options', + file: 'docs/kit/20-core-concepts/40-page-options.md', + }, + 'docs/kit/state-management': { + metadata: { title: 'State management' }, + slug: 'docs/kit/state-management', + file: 'docs/kit/20-core-concepts/50-state-management.md', + }, + 'docs/kit/remote-functions': { + metadata: { title: 'Remote functions' }, + slug: 'docs/kit/remote-functions', + file: 'docs/kit/20-core-concepts/60-remote-functions.md', + }, + 'docs/kit/building-your-app': { + metadata: { title: 'Building your app' }, + slug: 'docs/kit/building-your-app', + file: 'docs/kit/25-build-and-deploy/10-building-your-app.md', + }, + 'docs/kit/adapters': { + metadata: { title: 'Adapters' }, + slug: 'docs/kit/adapters', + file: 'docs/kit/25-build-and-deploy/20-adapters.md', + }, + 'docs/kit/adapter-auto': { + metadata: { title: 'Zero-config deployments' }, + slug: 'docs/kit/adapter-auto', + file: 'docs/kit/25-build-and-deploy/30-adapter-auto.md', + }, + 'docs/kit/adapter-node': { + metadata: { title: 'Node servers' }, + slug: 'docs/kit/adapter-node', + file: 'docs/kit/25-build-and-deploy/40-adapter-node.md', + }, + 'docs/kit/adapter-static': { + metadata: { title: 'Static site generation' }, + slug: 'docs/kit/adapter-static', + file: 'docs/kit/25-build-and-deploy/50-adapter-static.md', + }, + 'docs/kit/single-page-apps': { + metadata: { title: 'Single-page apps' }, + slug: 'docs/kit/single-page-apps', + file: 'docs/kit/25-build-and-deploy/55-single-page-apps.md', + }, + 'docs/kit/adapter-cloudflare': { + metadata: { title: 'Cloudflare' }, + slug: 'docs/kit/adapter-cloudflare', + file: 'docs/kit/25-build-and-deploy/60-adapter-cloudflare.md', + }, + 'docs/kit/adapter-cloudflare-workers': { + metadata: { title: 'Cloudflare Workers' }, + slug: 'docs/kit/adapter-cloudflare-workers', + file: 'docs/kit/25-build-and-deploy/70-adapter-cloudflare-workers.md', + }, + 'docs/kit/adapter-netlify': { + metadata: { title: 'Netlify' }, + slug: 'docs/kit/adapter-netlify', + file: 'docs/kit/25-build-and-deploy/80-adapter-netlify.md', + }, + 'docs/kit/adapter-vercel': { + metadata: { title: 'Vercel' }, + slug: 'docs/kit/adapter-vercel', + file: 'docs/kit/25-build-and-deploy/90-adapter-vercel.md', + }, + 'docs/kit/writing-adapters': { + metadata: { title: 'Writing adapters' }, + slug: 'docs/kit/writing-adapters', + file: 'docs/kit/25-build-and-deploy/99-writing-adapters.md', + }, + 'docs/kit/advanced-routing': { + metadata: { title: 'Advanced routing' }, + slug: 'docs/kit/advanced-routing', + file: 'docs/kit/30-advanced/10-advanced-routing.md', + }, + 'docs/kit/hooks': { + metadata: { title: 'Hooks' }, + slug: 'docs/kit/hooks', + file: 'docs/kit/30-advanced/20-hooks.md', + }, + 'docs/kit/errors': { + metadata: { title: 'Errors' }, + slug: 'docs/kit/errors', + file: 'docs/kit/30-advanced/25-errors.md', + }, + 'docs/kit/link-options': { + metadata: { title: 'Link options' }, + slug: 'docs/kit/link-options', + file: 'docs/kit/30-advanced/30-link-options.md', + }, + 'docs/kit/service-workers': { + metadata: { title: 'Service workers' }, + slug: 'docs/kit/service-workers', + file: 'docs/kit/30-advanced/40-service-workers.md', + }, + 'docs/kit/server-only-modules': { + metadata: { title: 'Server-only modules' }, + slug: 'docs/kit/server-only-modules', + file: 'docs/kit/30-advanced/50-server-only-modules.md', + }, + 'docs/kit/snapshots': { + metadata: { title: 'Snapshots' }, + slug: 'docs/kit/snapshots', + file: 'docs/kit/30-advanced/65-snapshots.md', + }, + 'docs/kit/shallow-routing': { + metadata: { title: 'Shallow routing' }, + slug: 'docs/kit/shallow-routing', + file: 'docs/kit/30-advanced/67-shallow-routing.md', + }, + 'docs/kit/observability': { + metadata: { title: 'Observability' }, + slug: 'docs/kit/observability', + file: 'docs/kit/30-advanced/68-observability.md', + }, + 'docs/kit/packaging': { + metadata: { title: 'Packaging' }, + slug: 'docs/kit/packaging', + file: 'docs/kit/30-advanced/70-packaging.md', + }, + 'docs/kit/auth': { + metadata: { title: 'Auth' }, + slug: 'docs/kit/auth', + file: 'docs/kit/40-best-practices/03-auth.md', + }, + 'docs/kit/performance': { + metadata: { title: 'Performance' }, + slug: 'docs/kit/performance', + file: 'docs/kit/40-best-practices/05-performance.md', + }, + 'docs/kit/icons': { + metadata: { title: 'Icons' }, + slug: 'docs/kit/icons', + file: 'docs/kit/40-best-practices/06-icons.md', + }, + 'docs/kit/images': { + metadata: { title: 'Images' }, + slug: 'docs/kit/images', + file: 'docs/kit/40-best-practices/07-images.md', + }, + 'docs/kit/accessibility': { + metadata: { title: 'Accessibility' }, + slug: 'docs/kit/accessibility', + file: 'docs/kit/40-best-practices/10-accessibility.md', + }, + 'docs/kit/seo': { + metadata: { title: 'SEO' }, + slug: 'docs/kit/seo', + file: 'docs/kit/40-best-practices/20-seo.md', + }, + 'docs/kit/faq': { + metadata: { title: 'Frequently asked questions' }, + slug: 'docs/kit/faq', + file: 'docs/kit/60-appendix/10-faq.md', + }, + 'docs/kit/integrations': { + metadata: { title: 'Integrations' }, + slug: 'docs/kit/integrations', + file: 'docs/kit/60-appendix/20-integrations.md', + }, + 'docs/kit/debugging': { + metadata: { title: 'Breakpoint Debugging' }, + slug: 'docs/kit/debugging', + file: 'docs/kit/60-appendix/25-debugging.md', + }, + 'docs/kit/migrating-to-sveltekit-2': { + metadata: { title: 'Migrating to SvelteKit v2' }, + slug: 'docs/kit/migrating-to-sveltekit-2', + file: 'docs/kit/60-appendix/30-migrating-to-sveltekit-2.md', + }, + 'docs/kit/migrating': { + metadata: { title: 'Migrating from Sapper' }, + slug: 'docs/kit/migrating', + file: 'docs/kit/60-appendix/40-migrating.md', + }, + 'docs/kit/additional-resources': { + metadata: { title: 'Additional resources' }, + slug: 'docs/kit/additional-resources', + file: 'docs/kit/60-appendix/50-additional-resources.md', + }, + 'docs/kit/glossary': { + metadata: { title: 'Glossary' }, + slug: 'docs/kit/glossary', + file: 'docs/kit/60-appendix/60-glossary.md', + }, + 'docs/kit/@sveltejs-kit': { + metadata: { title: '@sveltejs/kit' }, + slug: 'docs/kit/@sveltejs-kit', + file: 'docs/kit/98-reference/10-@sveltejs-kit.md', + }, + 'docs/kit/@sveltejs-kit-hooks': { + metadata: { title: '@sveltejs/kit/hooks' }, + slug: 'docs/kit/@sveltejs-kit-hooks', + file: 'docs/kit/98-reference/15-@sveltejs-kit-hooks.md', + }, + 'docs/kit/@sveltejs-kit-node-polyfills': { + metadata: { title: '@sveltejs/kit/node/polyfills' }, + slug: 'docs/kit/@sveltejs-kit-node-polyfills', + file: 'docs/kit/98-reference/15-@sveltejs-kit-node-polyfills.md', + }, + 'docs/kit/@sveltejs-kit-node': { + metadata: { title: '@sveltejs/kit/node' }, + slug: 'docs/kit/@sveltejs-kit-node', + file: 'docs/kit/98-reference/15-@sveltejs-kit-node.md', + }, + 'docs/kit/@sveltejs-kit-vite': { + metadata: { title: '@sveltejs/kit/vite' }, + slug: 'docs/kit/@sveltejs-kit-vite', + file: 'docs/kit/98-reference/15-@sveltejs-kit-vite.md', + }, + 'docs/kit/$app-environment': { + metadata: { title: '$app/environment' }, + slug: 'docs/kit/$app-environment', + file: 'docs/kit/98-reference/20-$app-environment.md', + }, + 'docs/kit/$app-forms': { + metadata: { title: '$app/forms' }, + slug: 'docs/kit/$app-forms', + file: 'docs/kit/98-reference/20-$app-forms.md', + }, + 'docs/kit/$app-navigation': { + metadata: { title: '$app/navigation' }, + slug: 'docs/kit/$app-navigation', + file: 'docs/kit/98-reference/20-$app-navigation.md', + }, + 'docs/kit/$app-paths': { + metadata: { title: '$app/paths' }, + slug: 'docs/kit/$app-paths', + file: 'docs/kit/98-reference/20-$app-paths.md', + }, + 'docs/kit/$app-server': { + metadata: { title: '$app/server' }, + slug: 'docs/kit/$app-server', + file: 'docs/kit/98-reference/20-$app-server.md', + }, + 'docs/kit/$app-state': { + metadata: { title: '$app/state' }, + slug: 'docs/kit/$app-state', + file: 'docs/kit/98-reference/20-$app-state.md', + }, + 'docs/kit/$app-stores': { + metadata: { title: '$app/stores' }, + slug: 'docs/kit/$app-stores', + file: 'docs/kit/98-reference/20-$app-stores.md', + }, + 'docs/kit/$app-types': { + metadata: { title: '$app/types' }, + slug: 'docs/kit/$app-types', + file: 'docs/kit/98-reference/20-$app-types.md', + }, + 'docs/kit/$env-dynamic-private': { + metadata: { title: '$env/dynamic/private' }, + slug: 'docs/kit/$env-dynamic-private', + file: 'docs/kit/98-reference/25-$env-dynamic-private.md', + }, + 'docs/kit/$env-dynamic-public': { + metadata: { title: '$env/dynamic/public' }, + slug: 'docs/kit/$env-dynamic-public', + file: 'docs/kit/98-reference/25-$env-dynamic-public.md', + }, + 'docs/kit/$env-static-private': { + metadata: { title: '$env/static/private' }, + slug: 'docs/kit/$env-static-private', + file: 'docs/kit/98-reference/25-$env-static-private.md', + }, + 'docs/kit/$env-static-public': { + metadata: { title: '$env/static/public' }, + slug: 'docs/kit/$env-static-public', + file: 'docs/kit/98-reference/25-$env-static-public.md', + }, + 'docs/kit/$lib': { + metadata: { title: '$lib' }, + slug: 'docs/kit/$lib', + file: 'docs/kit/98-reference/26-$lib.md', + }, + 'docs/kit/$service-worker': { + metadata: { title: '$service-worker' }, + slug: 'docs/kit/$service-worker', + file: 'docs/kit/98-reference/27-$service-worker.md', + }, + 'docs/kit/configuration': { + metadata: { title: 'Configuration' }, + slug: 'docs/kit/configuration', + file: 'docs/kit/98-reference/50-configuration.md', + }, + 'docs/kit/cli': { + metadata: { title: 'Command Line Interface' }, + slug: 'docs/kit/cli', + file: 'docs/kit/98-reference/52-cli.md', + }, + 'docs/kit/types': { + metadata: { title: 'Types' }, + slug: 'docs/kit/types', + file: 'docs/kit/98-reference/54-types.md', + }, + 'docs/svelte/overview': { + metadata: { title: 'Overview' }, + slug: 'docs/svelte/overview', + file: 'docs/svelte/01-introduction/01-overview.md', + }, + 'docs/svelte/getting-started': { + metadata: { title: 'Getting started' }, + slug: 'docs/svelte/getting-started', + file: 'docs/svelte/01-introduction/02-getting-started.md', + }, + 'docs/svelte/svelte-files': { + metadata: { title: '.svelte files' }, + slug: 'docs/svelte/svelte-files', + file: 'docs/svelte/01-introduction/03-svelte-files.md', + }, + 'docs/svelte/svelte-js-files': { + metadata: { title: '.svelte.js and .svelte.ts files' }, + slug: 'docs/svelte/svelte-js-files', + file: 'docs/svelte/01-introduction/04-svelte-js-files.md', + }, + 'docs/svelte/what-are-runes': { + metadata: { title: 'What are runes?' }, + slug: 'docs/svelte/what-are-runes', + file: 'docs/svelte/02-runes/01-what-are-runes.md', + }, + 'docs/svelte/$state': { + metadata: { title: '$state' }, + slug: 'docs/svelte/$state', + file: 'docs/svelte/02-runes/02-$state.md', + }, + 'docs/svelte/$derived': { + metadata: { title: '$derived' }, + slug: 'docs/svelte/$derived', + file: 'docs/svelte/02-runes/03-$derived.md', + }, + 'docs/svelte/$effect': { + metadata: { title: '$effect' }, + slug: 'docs/svelte/$effect', + file: 'docs/svelte/02-runes/04-$effect.md', + }, + 'docs/svelte/$props': { + metadata: { title: '$props' }, + slug: 'docs/svelte/$props', + file: 'docs/svelte/02-runes/05-$props.md', + }, + 'docs/svelte/$bindable': { + metadata: { title: '$bindable' }, + slug: 'docs/svelte/$bindable', + file: 'docs/svelte/02-runes/06-$bindable.md', + }, + 'docs/svelte/$inspect': { + metadata: { title: '$inspect' }, + slug: 'docs/svelte/$inspect', + file: 'docs/svelte/02-runes/07-$inspect.md', + }, + 'docs/svelte/$host': { + metadata: { title: '$host' }, + slug: 'docs/svelte/$host', + file: 'docs/svelte/02-runes/08-$host.md', + }, + 'docs/svelte/basic-markup': { + metadata: { title: 'Basic markup' }, + slug: 'docs/svelte/basic-markup', + file: 'docs/svelte/03-template-syntax/01-basic-markup.md', + }, + 'docs/svelte/if': { + metadata: { title: '{#if ...}' }, + slug: 'docs/svelte/if', + file: 'docs/svelte/03-template-syntax/02-if.md', + }, + 'docs/svelte/each': { + metadata: { title: '{#each ...}' }, + slug: 'docs/svelte/each', + file: 'docs/svelte/03-template-syntax/03-each.md', + }, + 'docs/svelte/key': { + metadata: { title: '{#key ...}' }, + slug: 'docs/svelte/key', + file: 'docs/svelte/03-template-syntax/04-key.md', + }, + 'docs/svelte/await': { + metadata: { title: '{#await ...}' }, + slug: 'docs/svelte/await', + file: 'docs/svelte/03-template-syntax/05-await.md', + }, + 'docs/svelte/snippet': { + metadata: { title: '{#snippet ...}' }, + slug: 'docs/svelte/snippet', + file: 'docs/svelte/03-template-syntax/06-snippet.md', + }, + 'docs/svelte/@render': { + metadata: { title: '{@render ...}' }, + slug: 'docs/svelte/@render', + file: 'docs/svelte/03-template-syntax/07-@render.md', + }, + 'docs/svelte/@html': { + metadata: { title: '{@html ...}' }, + slug: 'docs/svelte/@html', + file: 'docs/svelte/03-template-syntax/08-@html.md', + }, + 'docs/svelte/@attach': { + metadata: { title: '{@attach ...}' }, + slug: 'docs/svelte/@attach', + file: 'docs/svelte/03-template-syntax/09-@attach.md', + }, + 'docs/svelte/@const': { + metadata: { title: '{@const ...}' }, + slug: 'docs/svelte/@const', + file: 'docs/svelte/03-template-syntax/10-@const.md', + }, + 'docs/svelte/@debug': { + metadata: { title: '{@debug ...}' }, + slug: 'docs/svelte/@debug', + file: 'docs/svelte/03-template-syntax/11-@debug.md', + }, + 'docs/svelte/bind': { + metadata: { title: 'bind:' }, + slug: 'docs/svelte/bind', + file: 'docs/svelte/03-template-syntax/12-bind.md', + }, + 'docs/svelte/use': { + metadata: { title: 'use:' }, + slug: 'docs/svelte/use', + file: 'docs/svelte/03-template-syntax/13-use.md', + }, + 'docs/svelte/transition': { + metadata: { title: 'transition:' }, + slug: 'docs/svelte/transition', + file: 'docs/svelte/03-template-syntax/14-transition.md', + }, + 'docs/svelte/in-and-out': { + metadata: { title: 'in: and out:' }, + slug: 'docs/svelte/in-and-out', + file: 'docs/svelte/03-template-syntax/15-in-and-out.md', + }, + 'docs/svelte/animate': { + metadata: { title: 'animate:' }, + slug: 'docs/svelte/animate', + file: 'docs/svelte/03-template-syntax/16-animate.md', + }, + 'docs/svelte/style': { + metadata: { title: 'style:' }, + slug: 'docs/svelte/style', + file: 'docs/svelte/03-template-syntax/17-style.md', + }, + 'docs/svelte/class': { + metadata: { title: 'class' }, + slug: 'docs/svelte/class', + file: 'docs/svelte/03-template-syntax/18-class.md', + }, + 'docs/svelte/await-expressions': { + metadata: { title: 'await' }, + slug: 'docs/svelte/await-expressions', + file: 'docs/svelte/03-template-syntax/19-await-expressions.md', + }, + 'docs/svelte/scoped-styles': { + metadata: { title: 'Scoped styles' }, + slug: 'docs/svelte/scoped-styles', + file: 'docs/svelte/04-styling/01-scoped-styles.md', + }, + 'docs/svelte/global-styles': { + metadata: { title: 'Global styles' }, + slug: 'docs/svelte/global-styles', + file: 'docs/svelte/04-styling/02-global-styles.md', + }, + 'docs/svelte/custom-properties': { + metadata: { title: 'Custom properties' }, + slug: 'docs/svelte/custom-properties', + file: 'docs/svelte/04-styling/03-custom-properties.md', + }, + 'docs/svelte/nested-style-elements': { + metadata: { title: 'Nested