Skip to content

Commit 53f0fd8

Browse files
feat: add AGENTS.md for the mcp addon (#777)
Co-authored-by: jycouet <[email protected]>
1 parent 2c69299 commit 53f0fd8

File tree

7 files changed

+97
-20
lines changed

7 files changed

+97
-20
lines changed

.changeset/quick-comics-tell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'sv': patch
3+
---
4+
5+
feat(mcp): include an `AGENTS.md` or similar when using the `mcp` addon

documentation/docs/30-add-ons/17-mcp.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ npx sv add mcp
1212

1313
## What you get
1414

15-
- A good mcp configuration for your project depending on your IDE
15+
- A MCP configuration for [local](https://svelte.dev/docs/mcp/local-setup) or [remote](https://svelte.dev/docs/mcp/remote-setup) setup
16+
- A [README for agents](https://agents.md/) to help you use the MCP server effectively
1617

1718
## Options
1819

packages/addons/mcp/index.ts

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { defineAddon, defineAddonOptions } from '@sveltejs/cli-core';
1+
import { defineAddon, defineAddonOptions, log } from '@sveltejs/cli-core';
22
import { parseJson } from '@sveltejs/cli-core/parsers';
3+
import { getSharedFiles } from '../../create/utils.ts';
4+
import { getHighlighter } from '../../cli/commands/add/utils.ts';
35

46
const options = defineAddonOptions()
57
.add('ide', {
@@ -60,7 +62,8 @@ export default defineAddon({
6062
| {
6163
schema?: string;
6264
mcpServersKey?: string;
63-
filePath: string;
65+
agentPath: string;
66+
mcpPath: string;
6467
typeLocal?: 'stdio' | 'local';
6568
typeRemote?: 'http' | 'remote';
6669
env?: boolean;
@@ -70,48 +73,82 @@ export default defineAddon({
7073
| { other: true }
7174
> = {
7275
'claude-code': {
73-
filePath: '.mcp.json',
76+
agentPath: 'CLAUDE.md',
77+
mcpPath: '.mcp.json',
7478
typeLocal: 'stdio',
7579
typeRemote: 'http',
7680
env: true
7781
},
7882
cursor: {
79-
filePath: '.cursor/mcp.json'
83+
agentPath: 'AGENTS.md',
84+
mcpPath: '.cursor/mcp.json'
8085
},
8186
gemini: {
87+
agentPath: 'GEMINI.md',
8288
schema:
8389
'https://raw.githubusercontent.com/google-gemini/gemini-cli/main/schemas/settings.schema.json',
84-
filePath: '.gemini/settings.json'
90+
mcpPath: '.gemini/settings.json'
8591
},
8692
opencode: {
93+
agentPath: 'AGENTS.md',
8794
schema: 'https://opencode.ai/config.json',
8895
mcpServersKey: 'mcp',
89-
filePath: 'opencode.json',
96+
mcpPath: 'opencode.json',
9097
typeLocal: 'local',
9198
typeRemote: 'remote',
9299
command: ['npx', '-y', '@sveltejs/mcp'],
93100
args: null
94101
},
95102
vscode: {
103+
agentPath: 'AGENTS.md',
96104
mcpServersKey: 'servers',
97-
filePath: '.vscode/mcp.json'
105+
mcpPath: '.vscode/mcp.json'
98106
},
99107
other: {
100108
other: true
101109
}
102110
};
103111

112+
const filesAdded: string[] = [];
113+
const filesExistingAlready: string[] = [];
114+
115+
const sharedFiles = getSharedFiles().filter((file) => file.include.includes('mcp'));
116+
const agentFile = sharedFiles.find((file) => file.name === 'AGENTS.md');
117+
104118
for (const ide of options.ide) {
105119
const value = configurator[ide];
106120
if ('other' in value) continue;
107121

108-
const { mcpServersKey, filePath, typeLocal, typeRemote, env, schema, command, args } = value;
109-
sv.file(filePath, (content) => {
122+
const {
123+
mcpServersKey,
124+
agentPath,
125+
mcpPath,
126+
typeLocal,
127+
typeRemote,
128+
env,
129+
schema,
130+
command,
131+
args
132+
} = value;
133+
134+
// We only add the agent file if it's not already added
135+
if (!filesAdded.includes(agentPath)) {
136+
sv.file(agentPath, (content) => {
137+
if (content) {
138+
filesExistingAlready.push(agentPath);
139+
return content;
140+
}
141+
filesAdded.push(agentPath);
142+
return agentFile?.contents ?? '';
143+
});
144+
}
145+
146+
sv.file(mcpPath, (content) => {
110147
const { data, generateCode } = parseJson(content);
111148
if (schema) {
112149
data['$schema'] = schema;
113150
}
114-
const key = mcpServersKey || 'mcpServers';
151+
const key = mcpServersKey ?? 'mcpServers';
115152
data[key] ??= {};
116153
data[key].svelte =
117154
options.setup === 'local'
@@ -120,6 +157,14 @@ export default defineAddon({
120157
return generateCode();
121158
});
122159
}
160+
161+
if (filesExistingAlready.length > 0) {
162+
const highlighter = getHighlighter();
163+
log.warn(
164+
`${filesExistingAlready.map((path) => highlighter.path(path)).join(', ')} already exists, we didn't touch ${filesExistingAlready.length > 1 ? 'them' : 'it'}. ` +
165+
`See ${highlighter.website('https://svelte.dev/docs/mcp/overview#Usage')} for manual setup.`
166+
);
167+
}
123168
},
124169
nextSteps({ highlighter, options }) {
125170
const steps = [];

packages/create/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3-
import { mkdirp, copy, dist } from './utils.ts';
3+
import { mkdirp, copy, dist, getSharedFiles } from './utils.ts';
44

55
export type TemplateType = (typeof templateTypes)[number];
66
export type LanguageType = (typeof languageTypes)[number];
@@ -19,7 +19,7 @@ export type File = {
1919
contents: string;
2020
};
2121

22-
export type Condition = TemplateType | LanguageType | 'playground';
22+
export type Condition = TemplateType | LanguageType | 'playground' | 'mcp';
2323

2424
export type Common = {
2525
files: Array<{
@@ -66,8 +66,7 @@ function write_template_files(template: string, types: LanguageType, name: strin
6666
}
6767

6868
function write_common_files(cwd: string, options: Options, name: string) {
69-
const shared = dist('shared.json');
70-
const { files } = JSON.parse(fs.readFileSync(shared, 'utf-8')) as Common;
69+
const files = getSharedFiles();
7170

7271
const pkg_file = path.join(cwd, 'package.json');
7372
const pkg = /** @type {any} */ JSON.parse(fs.readFileSync(pkg_file, 'utf-8'));

packages/create/playground.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import path from 'node:path';
33
import * as js from '@sveltejs/cli-core/js';
44
import { parseJson, parseScript, parseSvelte } from '@sveltejs/cli-core/parsers';
55
import { isVersionUnsupportedBelow } from '@sveltejs/cli-core';
6-
import { dist } from './utils.ts';
7-
import type { Common } from './index.ts';
6+
import { getSharedFiles } from './utils.ts';
87

98
export function validatePlaygroundUrl(link: string): boolean {
109
try {
@@ -182,9 +181,7 @@ export function setupPlaygroundProject(
182181

183182
// add playground shared files
184183
{
185-
const shared = dist('shared.json');
186-
const { files } = JSON.parse(fs.readFileSync(shared, 'utf-8')) as Common;
187-
const playgroundFiles = files.filter((file) => file.include.includes('playground'));
184+
const playgroundFiles = getSharedFiles().filter((file) => file.include.includes('playground'));
188185

189186
for (const file of playgroundFiles) {
190187
let contentToWrite = file.contents;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
You are able to use the Svelte MCP server, where you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
2+
3+
## Available MCP Tools:
4+
5+
### 1. list-sections
6+
7+
Use this FIRST to discover all available documentation sections. Returns a structured list with titles, use_cases, and paths.
8+
When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections.
9+
10+
### 2. get-documentation
11+
12+
Retrieves full documentation content for specific sections. Accepts single or multiple sections.
13+
After calling the list-sections tool, you MUST analyze the returned documentation sections (especially the use_cases field) and then use the get-documentation tool to fetch ALL documentation sections that are relevant for the user's task.
14+
15+
### 3. svelte-autofixer
16+
17+
Analyzes Svelte code and returns issues and suggestions.
18+
You MUST use this tool whenever writing Svelte code before sending it to the user. Keep calling it until no issues or suggestions are returned.
19+
20+
### 4. playground-link
21+
22+
Generates a Svelte Playground link with the provided code.
23+
After completing the code, ask the user if they want a playground link. Only call this tool after user confirmation and NEVER if code was written to files in their project.

packages/create/utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
33
import { fileURLToPath } from 'node:url';
4+
import type { Common } from './index.ts';
45

56
export function mkdirp(dir: string): void {
67
try {
@@ -44,3 +45,9 @@ export function dist(path: string): string {
4445
new URL(`./${!insideDistFolder ? 'dist/' : ''}${path}`, import.meta.url).href
4546
);
4647
}
48+
49+
export function getSharedFiles(): Common['files'] {
50+
const shared = dist('shared.json');
51+
const { files } = JSON.parse(fs.readFileSync(shared, 'utf-8')) as Common;
52+
return files;
53+
}

0 commit comments

Comments
 (0)