mirror of
https://github.com/sveltejs/ai-tools.git
synced 2026-07-04 03:19:38 +08:00
Compare commits
7 Commits
remove-db-
...
stdio-read
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cfc0e4887 | ||
|
|
23615de20c | ||
|
|
a3bc42c70e | ||
|
|
22da6bbb3c | ||
|
|
e640b70d78 | ||
|
|
dd4d81a2bd | ||
|
|
e429cd7839 |
5
.changeset/giant-monkeys-end.md
Normal file
5
.changeset/giant-monkeys-end.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@sveltejs/mcp': patch
|
||||
---
|
||||
|
||||
feat: allow stdio mcp to read the content of the file directly
|
||||
5
.changeset/small-actors-notice.md
Normal file
5
.changeset/small-actors-notice.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@sveltejs/mcp': patch
|
||||
---
|
||||
|
||||
chore: remove db requirement
|
||||
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
@@ -32,6 +32,4 @@ jobs:
|
||||
- name: Run type check
|
||||
run: pnpm run check
|
||||
env:
|
||||
DATABASE_URL: file:test.db
|
||||
DATABASE_TOKEN: dummy-key
|
||||
VOYAGE_API_KEY: dummy-key
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -32,6 +32,4 @@ jobs:
|
||||
- name: Run linting
|
||||
run: pnpm run lint
|
||||
env:
|
||||
DATABASE_URL: file:test.db
|
||||
VOYAGE_API_KEY: dummy-key
|
||||
DATABASE_TOKEN: dummy-key
|
||||
|
||||
3
.github/workflows/publish-any-commit.yml
vendored
3
.github/workflows/publish-any-commit.yml
vendored
@@ -19,5 +19,8 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
# Opencode doesn't have a build step
|
||||
- name: Build Stdio
|
||||
run: pnpm --filter @sveltejs/mcp run build
|
||||
|
||||
- run: pnpm dlx pkg-pr-new publish --compact './packages/mcp-stdio' './packages/opencode' --pnpm
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -32,13 +32,9 @@ jobs:
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
env:
|
||||
DATABASE_URL: file:test.db
|
||||
VOYAGE_API_KEY: dummy-key
|
||||
DATABASE_TOKEN: dummy-key
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm run test
|
||||
env:
|
||||
DATABASE_URL: file:test.db
|
||||
VOYAGE_API_KEY: dummy-key
|
||||
DATABASE_TOKEN: dummy-key
|
||||
|
||||
@@ -83,7 +83,6 @@ Located in `src/lib/server/analyze/`:
|
||||
|
||||
Required environment variables:
|
||||
|
||||
- `DATABASE_URL`: SQLite database path (default: `file:test.db`)
|
||||
- `VOYAGE_API_KEY`: API key for embeddings support (optional)
|
||||
|
||||
When connected to the svelte-llm MCP server, you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
DATABASE_URL=file:test.db
|
||||
DATABASE_TOKEN=needs_to_be_set_but_it_can_be_anything
|
||||
VOYAGE_API_KEY=your_actual_api_key_here
|
||||
@@ -1,12 +0,0 @@
|
||||
import { defineConfig } from 'drizzle-kit';
|
||||
|
||||
if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set');
|
||||
if (!process.env.DATABASE_TOKEN) throw new Error('DATABASE_TOKEN is not set');
|
||||
|
||||
export default defineConfig({
|
||||
schema: './src/lib/server/db/schema.ts',
|
||||
dialect: 'turso',
|
||||
dbCredentials: { url: process.env.DATABASE_URL, authToken: process.env.DATABASE_TOKEN },
|
||||
verbose: true,
|
||||
strict: true,
|
||||
});
|
||||
@@ -23,10 +23,6 @@
|
||||
"test:unit": "vitest",
|
||||
"test": "npm run test:unit -- --run",
|
||||
"test:watch": "npm run test:unit -- --watch",
|
||||
"db:push": "drizzle-kit push",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"inspect": "pnpm mcp-inspector"
|
||||
},
|
||||
"keywords": [
|
||||
@@ -39,15 +35,12 @@
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "catalog:lint",
|
||||
"@eslint/js": "catalog:lint",
|
||||
"@libsql/client": "catalog:orm",
|
||||
"@modelcontextprotocol/inspector": "catalog:ai",
|
||||
"@sveltejs/adapter-vercel": "catalog:svelte",
|
||||
"@sveltejs/kit": "catalog:svelte",
|
||||
"@sveltejs/vite-plugin-svelte": "catalog:svelte",
|
||||
"@types/node": "catalog:tooling",
|
||||
"@typescript-eslint/parser": "catalog:lint",
|
||||
"drizzle-kit": "catalog:orm",
|
||||
"drizzle-orm": "catalog:orm",
|
||||
"eslint-config-prettier": "catalog:lint",
|
||||
"eslint-plugin-svelte": "catalog:lint",
|
||||
"globals": "catalog:lint",
|
||||
@@ -62,7 +55,6 @@
|
||||
"vitest": "catalog:tooling"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sveltejs/mcp-schema": "workspace:^",
|
||||
"@sveltejs/mcp-server": "workspace:^",
|
||||
"@tmcp/transport-http": "catalog:tmcp",
|
||||
"@vercel/analytics": "catalog:tooling",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { dev } from '$app/environment';
|
||||
import { http_transport } from '$lib/mcp/index.js';
|
||||
import { db } from '$lib/server/db/index.js';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { track } from '@vercel/analytics/server';
|
||||
|
||||
@@ -17,7 +16,6 @@ export async function handle({ event, resolve }) {
|
||||
}
|
||||
}
|
||||
const mcp_response = await http_transport.respond(event.request, {
|
||||
db,
|
||||
// only add analytics in production
|
||||
track: dev
|
||||
? undefined
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { createClient } from '@libsql/client';
|
||||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
import * as schema from './schema.js';
|
||||
import { DATABASE_TOKEN, DATABASE_URL } from '$env/static/private';
|
||||
if (!DATABASE_URL) throw new Error('DATABASE_URL is not set');
|
||||
if (!DATABASE_TOKEN) throw new Error('DATABASE_TOKEN is not set');
|
||||
|
||||
const client = createClient({
|
||||
url: DATABASE_URL,
|
||||
authToken: DATABASE_TOKEN,
|
||||
});
|
||||
|
||||
export const db = drizzle(client, { schema, logger: true });
|
||||
@@ -1,2 +0,0 @@
|
||||
// we need to re-export from here to allow for the drizzle config to pick them up for migrations
|
||||
export * from '@sveltejs/mcp-schema/schema';
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "@sveltejs/mcp-schema",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
".": "./src/index.js",
|
||||
"./utils": "./src/utils.js",
|
||||
"./schema": "./src/schema.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"drizzle-orm": "catalog:orm"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* @import * as schema from './schema.js'
|
||||
*/
|
||||
export * from './schema.js';
|
||||
|
||||
/**
|
||||
* @typedef {typeof schema} Schema
|
||||
*/
|
||||
@@ -1,82 +0,0 @@
|
||||
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
import { float_32_array } from './utils.js';
|
||||
|
||||
/**
|
||||
* NOTE: if you modify a schema adding a vector column you need to manually add this
|
||||
*
|
||||
* CREATE INDEX IF NOT EXISTS name_of_the_index
|
||||
* ON `name_of_the_table` (
|
||||
* libsql_vector_idx(name_of_the_column, 'metric=cosine')
|
||||
* )
|
||||
*
|
||||
* to the generated migration file
|
||||
*/
|
||||
|
||||
export const distillations = sqliteTable('distillations', {
|
||||
id: integer('id').primaryKey(),
|
||||
preset_name: text('preset_name').notNull(),
|
||||
version: text('version').notNull(),
|
||||
content: text('content').notNull(),
|
||||
size_kb: integer('size_kb').notNull(),
|
||||
document_count: integer('document_count').notNull(),
|
||||
distillation_job_id: integer('distillation_job_id').references(() => distillation_jobs.id),
|
||||
created_at: integer('created_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
});
|
||||
|
||||
export const distillation_jobs = sqliteTable('distillation_jobs', {
|
||||
id: integer('id').primaryKey(),
|
||||
preset_name: text('preset_name').notNull(),
|
||||
batch_id: text('batch_id'),
|
||||
status: text('status', { enum: ['pending', 'processing', 'completed', 'failed'] }).notNull(),
|
||||
model_used: text('model_used').notNull(),
|
||||
total_files: integer('total_files').notNull(),
|
||||
processed_files: integer('processed_files').notNull().default(0),
|
||||
successful_files: integer('successful_files').notNull().default(0),
|
||||
minimize_applied: integer('minimize_applied', { mode: 'boolean' }).notNull().default(false),
|
||||
total_input_tokens: integer('total_input_tokens').notNull().default(0),
|
||||
total_output_tokens: integer('total_output_tokens').notNull().default(0),
|
||||
started_at: integer('started_at', { mode: 'timestamp' }),
|
||||
completed_at: integer('completed_at', { mode: 'timestamp' }),
|
||||
error_message: text('error_message'),
|
||||
metadata: text('metadata', { mode: 'json' }).notNull().default({}),
|
||||
created_at: integer('created_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
updated_at: integer('updated_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
});
|
||||
|
||||
export const content = sqliteTable('content', {
|
||||
id: integer('id').primaryKey(),
|
||||
path: text('path').notNull(),
|
||||
filename: text('filename').notNull(),
|
||||
content: text('content').notNull(),
|
||||
size_bytes: integer('size_bytes').notNull(),
|
||||
embeddings: float_32_array('embeddings', { dimensions: 1024 }),
|
||||
metadata: text('metadata', { mode: 'json' }).notNull().default({}),
|
||||
created_at: integer('created_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
updated_at: integer('updated_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
});
|
||||
|
||||
export const content_distilled = sqliteTable('content_distilled', {
|
||||
id: integer('id').primaryKey(),
|
||||
path: text('path').notNull(),
|
||||
filename: text('filename').notNull(),
|
||||
content: text('content').notNull(),
|
||||
size_bytes: integer('size_bytes').notNull(),
|
||||
embeddings: float_32_array('embeddings', { dimensions: 1024 }),
|
||||
metadata: text('metadata', { mode: 'json' }).notNull().default({}),
|
||||
created_at: integer('created_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
updated_at: integer('updated_at', { mode: 'timestamp' })
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date()),
|
||||
});
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* @import { Column } from 'drizzle-orm';
|
||||
*/
|
||||
import { sql } from 'drizzle-orm';
|
||||
import { customType } from 'drizzle-orm/sqlite-core';
|
||||
|
||||
/**
|
||||
* Helper function to convert an array of embeddings into a format that can be inserted into a LibSQL vector column.
|
||||
* @param {number[]} arr The embeddings array.
|
||||
*/
|
||||
export function vector(arr) {
|
||||
return sql`vector32(${JSON.stringify(arr)})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to calculate the distance between a vector column and an array of embeddings and return it as a columns.
|
||||
* @param {Column} column The drizzle column representing the vector.
|
||||
* @param {number} arr The embeddings array.
|
||||
* @param {string} as The name of the returned column. Default is 'distance'.
|
||||
*
|
||||
* @example
|
||||
* await db.select({
|
||||
* id: vector_table.id,
|
||||
* text: vector_table.text,
|
||||
* distance: distance(vector_table.vector, await get_embeddings(sentence)),
|
||||
* })
|
||||
* .from(vector_table)
|
||||
* .orderBy(sql`distance`)
|
||||
* .execute();
|
||||
*/
|
||||
export function distance(column, arr, as = 'distance') {
|
||||
return /** @type {typeof sql<number>} */ (
|
||||
sql
|
||||
)`CASE ${column} ISNULL WHEN 1 THEN 1 ELSE vector_distance_cos(${column}, vector32(${JSON.stringify(arr)})) END`.as(
|
||||
as,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom drizzle type to use the LibSQL vector column type.
|
||||
*/
|
||||
export const float_32_array = /** @type {typeof customType<{
|
||||
data: number[];
|
||||
config: { dimensions: number };
|
||||
configRequired: true;
|
||||
driverData: Buffer;
|
||||
}>} */ (customType)({
|
||||
dataType(config) {
|
||||
return `F32_BLOB(${config.dimensions})`;
|
||||
},
|
||||
/**
|
||||
* @param {Buffer} value
|
||||
*/
|
||||
fromDriver(value) {
|
||||
return Array.from(new Float32Array(value.buffer));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {number[]} value
|
||||
* @returns
|
||||
*/
|
||||
toDriver(value) {
|
||||
return vector(value);
|
||||
},
|
||||
});
|
||||
@@ -17,12 +17,8 @@
|
||||
".": "./src/index.ts",
|
||||
"./handlers": "./src/mcp/handlers/tools/handlers.ts"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"drizzle-orm": "^0.45.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mcp-ui/server": "catalog:ai",
|
||||
"@sveltejs/mcp-schema": "workspace:^",
|
||||
"@tmcp/adapter-valibot": "catalog:tmcp",
|
||||
"@tmcp/transport-in-memory": "catalog:tmcp",
|
||||
"@typescript-eslint/parser": "catalog:lint",
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { writeFileSync, unlinkSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { InMemoryTransport } from '@tmcp/transport-in-memory';
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { server } from '../../index.js';
|
||||
@@ -12,13 +15,18 @@ async function autofixer_tool_call(
|
||||
is_error = false,
|
||||
desired_svelte_version = 5,
|
||||
async = false,
|
||||
ctx?: { stdio?: boolean },
|
||||
) {
|
||||
const result = await session.callTool('svelte-autofixer', {
|
||||
code,
|
||||
desired_svelte_version,
|
||||
filename: 'App.svelte',
|
||||
async,
|
||||
});
|
||||
const result = await session.callTool(
|
||||
'svelte-autofixer',
|
||||
{
|
||||
code,
|
||||
desired_svelte_version,
|
||||
filename: 'App.svelte',
|
||||
async,
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
if (is_error) {
|
||||
@@ -146,4 +154,40 @@ describe('svelte-autofixer tool', () => {
|
||||
'The desired_svelte_version MUST be either 4 or 5 but received "3"',
|
||||
);
|
||||
});
|
||||
|
||||
it('should read file content from path when stdio context is true', async () => {
|
||||
const tmp_file = join(tmpdir(), `svelte-autofixer-test-${Date.now()}.svelte`);
|
||||
const file_content = `<script>
|
||||
$state count = 0;
|
||||
</script>`;
|
||||
|
||||
writeFileSync(tmp_file, file_content, 'utf-8');
|
||||
|
||||
try {
|
||||
// with stdio: true, the file is read from disk and parsed, producing issues
|
||||
const content = await autofixer_tool_call(tmp_file, false, 5, false, { stdio: true });
|
||||
expect(content.issues.length).toBeGreaterThan(0);
|
||||
expect(content.suggestions.length).toBeGreaterThan(0);
|
||||
} finally {
|
||||
unlinkSync(tmp_file);
|
||||
}
|
||||
});
|
||||
|
||||
it('should treat file path as code when stdio context is not set', async () => {
|
||||
const tmp_file = join(tmpdir(), `svelte-autofixer-test-${Date.now()}.svelte`);
|
||||
const file_content = `<script>
|
||||
$state count = 0;
|
||||
</script>`;
|
||||
|
||||
writeFileSync(tmp_file, file_content, 'utf-8');
|
||||
|
||||
try {
|
||||
// without stdio context, the path string is treated as raw code (plain text), no issues
|
||||
const content = await autofixer_tool_call(tmp_file, false, 5, false);
|
||||
expect(content.issues).toHaveLength(0);
|
||||
expect(content.suggestions).toHaveLength(0);
|
||||
} finally {
|
||||
unlinkSync(tmp_file);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,33 +1,47 @@
|
||||
import { basename } from 'node:path';
|
||||
import type { SvelteMcp } from '../../index.js';
|
||||
import { tool } from 'tmcp/utils';
|
||||
import * as v from 'valibot';
|
||||
import { add_autofixers_issues } from '../../autofixers/add-autofixers-issues.js';
|
||||
import { add_compile_issues } from '../../autofixers/add-compile-issues.js';
|
||||
import { add_eslint_issues } from '../../autofixers/add-eslint-issues.js';
|
||||
import { add_autofixers_issues } from '../../autofixers/add-autofixers-issues.js';
|
||||
import { icons } from '../../icons/index.js';
|
||||
import { tool } from 'tmcp/utils';
|
||||
import { type SvelteMcp } from '../../index.js';
|
||||
|
||||
const autofixer_schema = v.object({
|
||||
code: v.string(),
|
||||
desired_svelte_version: v.pipe(
|
||||
v.union([v.string(), v.number()]),
|
||||
v.description(
|
||||
'The desired svelte version...if possible read this from the package.json of the user project, otherwise use some hint from the wording (if the user asks for runes it wants version 5). Default to 5 in case of doubt.',
|
||||
let cached_schema: ReturnType<typeof get_autofixer_schema> | null = null;
|
||||
|
||||
function get_autofixer_schema(stdio: boolean) {
|
||||
let code = v.string();
|
||||
if (stdio) {
|
||||
// we only add the description if we are running in stdio, this saves a few tokens for the remote server
|
||||
code = v.pipe(
|
||||
v.string(),
|
||||
v.description(
|
||||
"The code to be processed by the autofixer. It can also be a path to a file containing the code. If the file doesn't exists the string will be treated as the code",
|
||||
),
|
||||
);
|
||||
}
|
||||
return v.object({
|
||||
code,
|
||||
desired_svelte_version: v.pipe(
|
||||
v.union([v.string(), v.number()]),
|
||||
v.description(
|
||||
'The desired svelte version...if possible read this from the package.json of the user project, otherwise use some hint from the wording (if the user asks for runes it wants version 5). Default to 5 in case of doubt.',
|
||||
),
|
||||
),
|
||||
),
|
||||
async: v.pipe(
|
||||
v.optional(v.boolean()),
|
||||
v.description(
|
||||
'If true the code is an async component/module and might use await in the markup or top-level awaits in the script tag. If possible check the svelte.config.js/svelte.config.ts to check if the option is enabled otherwise asks the user if they prefer using it or not. You can only use this option if the version is 5.',
|
||||
async: v.pipe(
|
||||
v.optional(v.boolean()),
|
||||
v.description(
|
||||
'If true the code is an async component/module and might use await in the markup or top-level awaits in the script tag. If possible check the svelte.config.js/svelte.config.ts to check if the option is enabled otherwise asks the user if they prefer using it or not. You can only use this option if the version is 5.',
|
||||
),
|
||||
),
|
||||
),
|
||||
filename: v.pipe(
|
||||
v.optional(v.string()),
|
||||
v.description(
|
||||
'The filename of the component if available, it MUST be only the Component name with .svelte or .svelte.ts extension and not the entire path.',
|
||||
filename: v.pipe(
|
||||
v.optional(v.string()),
|
||||
v.description(
|
||||
'The filename of the component if available, it MUST be only the Component name with .svelte or .svelte.ts extension and not the entire path.',
|
||||
),
|
||||
),
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const autofixer_output_schema = v.object({
|
||||
issues: v.array(v.string()),
|
||||
@@ -40,7 +54,7 @@ export async function svelte_autofixer_handler({
|
||||
desired_svelte_version: desired_svelte_version_unchecked,
|
||||
async,
|
||||
filename: filename_or_path,
|
||||
}: v.InferInput<typeof autofixer_schema>) {
|
||||
}: v.InferInput<ReturnType<typeof get_autofixer_schema>>) {
|
||||
// we validate manually because some clients don't support union in the input schema (looking at you cursor)
|
||||
const parsed_version = v.safeParse(
|
||||
v.union([v.literal(4), v.literal(5), v.literal('4'), v.literal('5')]),
|
||||
@@ -110,7 +124,11 @@ export function svelte_autofixer(server: SvelteMcp) {
|
||||
title: 'Svelte Autofixer',
|
||||
description:
|
||||
'Given a svelte component or module returns a list of suggestions to fix any issues it has. This tool MUST be used whenever the user is asking to write svelte code before sending the code back to the user',
|
||||
schema: autofixer_schema,
|
||||
get schema() {
|
||||
return (
|
||||
cached_schema ?? (cached_schema = get_autofixer_schema(server.ctx.custom?.stdio ?? false))
|
||||
);
|
||||
},
|
||||
outputSchema: autofixer_output_schema,
|
||||
annotations: {
|
||||
title: 'Svelte Autofixer',
|
||||
@@ -129,6 +147,18 @@ export function svelte_autofixer(server: SvelteMcp) {
|
||||
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||
await server.ctx.custom?.track?.(server.ctx.sessionId, 'svelte-autofixer');
|
||||
}
|
||||
|
||||
// we only do this if we know we are running in stdio mode (only stdio pass the context as true)
|
||||
if (server.ctx.custom?.stdio) {
|
||||
const [exists_sync, read_file] = await Promise.all([
|
||||
import('node:fs').then((mod) => mod.existsSync),
|
||||
import('node:fs/promises').then((mod) => mod.readFile),
|
||||
]);
|
||||
if (exists_sync(code)) {
|
||||
code = await read_file(code, 'utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const content = await svelte_autofixer_handler({
|
||||
code,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot';
|
||||
import { McpServer } from 'tmcp';
|
||||
import { setup_prompts, setup_resources, setup_tools } from './handlers/index.js';
|
||||
import type { LibSQLDatabase } from 'drizzle-orm/libsql';
|
||||
import type { Schema } from '@sveltejs/mcp-schema';
|
||||
import { icons } from './icons/index.js';
|
||||
|
||||
export const server = new McpServer(
|
||||
@@ -25,8 +23,8 @@ export const server = new McpServer(
|
||||
'This is the official Svelte MCP server. It MUST be used whenever svelte development is involved. It can provide official documentation, code examples and correct your code. After you correct the component call this tool again to confirm all the issues are fixed.',
|
||||
},
|
||||
).withContext<{
|
||||
db: LibSQLDatabase<Schema>;
|
||||
track?: (sessionId: string, event: string, extra?: string) => Promise<void>;
|
||||
stdio?: boolean;
|
||||
}>();
|
||||
|
||||
export type SvelteMcp = typeof server;
|
||||
|
||||
@@ -14,7 +14,9 @@ const cli = sade('svelte-mcp');
|
||||
|
||||
cli.command('__mcp', '', { default: true }).action(() => {
|
||||
const transport = new StdioTransport(server);
|
||||
transport.listen();
|
||||
transport.listen({
|
||||
stdio: true,
|
||||
});
|
||||
});
|
||||
|
||||
cli
|
||||
|
||||
673
pnpm-lock.yaml
generated
673
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -24,10 +24,6 @@ catalogs:
|
||||
prettier-plugin-svelte: ^3.3.3
|
||||
svelte-eslint-parser: ^1.4.0
|
||||
typescript-eslint: ^8.44.0
|
||||
orm:
|
||||
'@libsql/client': ^0.17.0
|
||||
drizzle-kit: ^0.31.0
|
||||
drizzle-orm: ^0.45.0
|
||||
svelte:
|
||||
'@sveltejs/adapter-vercel': ^6.0.0
|
||||
'@sveltejs/kit': ^2.42.2
|
||||
@@ -35,11 +31,11 @@ catalogs:
|
||||
svelte: ^5.47.0
|
||||
svelte-check: ^4.0.0
|
||||
tmcp:
|
||||
'@tmcp/adapter-valibot': ^0.1.4
|
||||
'@tmcp/transport-http': ^0.8.4
|
||||
'@tmcp/transport-in-memory': ^0.0.5
|
||||
'@tmcp/transport-stdio': ^0.4.0
|
||||
tmcp: ^1.19.0
|
||||
'@tmcp/adapter-valibot': ^0.1.5
|
||||
'@tmcp/transport-http': ^0.8.5
|
||||
'@tmcp/transport-in-memory': ^0.0.6
|
||||
'@tmcp/transport-stdio': ^0.4.2
|
||||
tmcp: ^1.19.3
|
||||
tooling:
|
||||
'@changesets/cli': ^2.29.7
|
||||
'@svitejs/changesets-changelog-github-compact': ^1.2.0
|
||||
|
||||
Reference in New Issue
Block a user