Skip to content

Commit 975488f

Browse files
committed
fix: update yarn.lock with template dependencies
- Remove wayback-specific dependencies (chalk, commander, ora) - Add template dependencies (biome, husky, zod-to-json-schema) - Fix dependency installation issues in CI
1 parent ee1dcd8 commit 975488f

File tree

9 files changed

+255
-295
lines changed

9 files changed

+255
-295
lines changed

package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,7 @@
1515
"prepare": "husky",
1616
"start": "node dist/index.js"
1717
},
18-
"keywords": [
19-
"mcp",
20-
"model-context-protocol",
21-
"typescript",
22-
"template",
23-
"mcp-server"
24-
],
18+
"keywords": ["mcp", "model-context-protocol", "typescript", "template", "mcp-server"],
2519
"author": "",
2620
"license": "MIT",
2721
"repository": {

src/index.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, expect, it } from 'vitest';
22

33
describe('MCP Server', () => {
4-
it('should export as ES module', async () => {
5-
// This test verifies the module can be imported
6-
const module = await import('./index.js');
7-
expect(module).toBeDefined();
8-
});
9-
});
4+
it('should export as ES module', async () => {
5+
// This test verifies the module can be imported
6+
const module = await import('./index.js');
7+
expect(module).toBeDefined();
8+
});
9+
});

src/index.ts

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,46 @@
11
#!/usr/bin/env node
22
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
33
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4-
import {
5-
CallToolRequestSchema,
6-
ListToolsRequestSchema,
7-
} from '@modelcontextprotocol/sdk/types.js';
4+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
85
import { z } from 'zod';
96
import { zodToJsonSchema } from 'zod-to-json-schema';
10-
import { exampleTool, ExampleToolSchema } from './tools/example.js';
7+
import { ExampleToolSchema, exampleTool } from './tools/example.js';
118

129
const server = new Server(
13-
{
14-
name: 'mcp-template',
15-
version: '0.1.0',
16-
},
17-
{
18-
capabilities: {
19-
tools: {},
20-
},
21-
}
10+
{
11+
name: 'mcp-template',
12+
version: '0.1.0',
13+
},
14+
{
15+
capabilities: {
16+
tools: {},
17+
},
18+
},
2219
);
2320

2421
// List available tools
2522
server.setRequestHandler(ListToolsRequestSchema, async () => {
26-
return {
27-
tools: [
28-
{
29-
name: 'example_tool',
30-
description: 'An example tool that echoes back the input',
31-
inputSchema: zodToJsonSchema(ExampleToolSchema),
32-
},
33-
],
34-
};
23+
return {
24+
tools: [
25+
{
26+
name: 'example_tool',
27+
description: 'An example tool that echoes back the input',
28+
inputSchema: zodToJsonSchema(ExampleToolSchema),
29+
},
30+
],
31+
};
3532
});
3633

3734
// Handle tool calls
3835
server.setRequestHandler(CallToolRequestSchema, async (request) => {
39-
const { name, arguments: args } = request.params;
36+
const { name, arguments: args } = request.params;
4037

41-
switch (name) {
42-
case 'example_tool':
43-
return await exampleTool(args);
44-
default:
45-
throw new Error(`Unknown tool: ${name}`);
46-
}
38+
switch (name) {
39+
case 'example_tool':
40+
return await exampleTool(args);
41+
default:
42+
throw new Error(`Unknown tool: ${name}`);
43+
}
4744
});
4845

4946
// Start the server
@@ -52,6 +49,6 @@ await server.connect(transport);
5249

5350
// Handle shutdown gracefully
5451
process.on('SIGINT', async () => {
55-
await server.close();
56-
process.exit(0);
57-
});
52+
await server.close();
53+
process.exit(0);
54+
});

src/tools/example.test.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, expect, it } from 'vitest';
22
import { exampleTool } from './example.js';
33

44
describe('exampleTool', () => {
5-
it('should echo the message', async () => {
6-
const result = await exampleTool({ message: 'Hello, world!' });
7-
expect(result.content[0]).toEqual({
8-
type: 'text',
9-
text: 'Echo: Hello, world!',
10-
});
11-
});
5+
it('should echo the message', async () => {
6+
const result = await exampleTool({ message: 'Hello, world!' });
7+
expect(result.content[0]).toEqual({
8+
type: 'text',
9+
text: 'Echo: Hello, world!',
10+
});
11+
});
1212

13-
it('should convert to uppercase when requested', async () => {
14-
const result = await exampleTool({
15-
message: 'Hello, world!',
16-
uppercase: true,
17-
});
18-
expect(result.content[0]).toEqual({
19-
type: 'text',
20-
text: 'Echo: HELLO, WORLD!',
21-
});
22-
});
13+
it('should convert to uppercase when requested', async () => {
14+
const result = await exampleTool({
15+
message: 'Hello, world!',
16+
uppercase: true,
17+
});
18+
expect(result.content[0]).toEqual({
19+
type: 'text',
20+
text: 'Echo: HELLO, WORLD!',
21+
});
22+
});
2323

24-
it('should validate input', async () => {
25-
await expect(exampleTool({})).rejects.toThrow();
26-
await expect(exampleTool({ message: 123 })).rejects.toThrow();
27-
});
28-
});
24+
it('should validate input', async () => {
25+
await expect(exampleTool({})).rejects.toThrow();
26+
await expect(exampleTool({ message: 123 })).rejects.toThrow();
27+
});
28+
});

src/tools/example.ts

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
import { z } from 'zod';
22

33
export const ExampleToolSchema = z.object({
4-
message: z.string().describe('The message to echo back'),
5-
uppercase: z.boolean().optional().default(false).describe('Whether to return the message in uppercase'),
4+
message: z.string().describe('The message to echo back'),
5+
uppercase: z
6+
.boolean()
7+
.optional()
8+
.default(false)
9+
.describe('Whether to return the message in uppercase'),
610
});
711

812
export type ExampleToolInput = z.infer<typeof ExampleToolSchema>;
913

1014
export async function exampleTool(args: unknown) {
11-
const input = ExampleToolSchema.parse(args);
12-
13-
let result = input.message;
14-
if (input.uppercase) {
15-
result = result.toUpperCase();
16-
}
17-
18-
return {
19-
content: [
20-
{
21-
type: 'text',
22-
text: `Echo: ${result}`,
23-
},
24-
],
25-
};
26-
}
15+
const input = ExampleToolSchema.parse(args);
16+
17+
let result = input.message;
18+
if (input.uppercase) {
19+
result = result.toUpperCase();
20+
}
21+
22+
return {
23+
content: [
24+
{
25+
type: 'text',
26+
text: `Echo: ${result}`,
27+
},
28+
],
29+
};
30+
}

src/utils/validation.test.ts

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,51 @@
1-
import { describe, it, expect } from 'vitest';
2-
import { urlSchema, dateSchema, timestampSchema, validateInput } from './validation.js';
1+
import { describe, expect, it } from 'vitest';
2+
import { dateSchema, timestampSchema, urlSchema, validateInput } from './validation.js';
33

44
describe('validation schemas', () => {
5-
describe('urlSchema', () => {
6-
it('should accept valid URLs', () => {
7-
expect(urlSchema.parse('https://example.com')).toBe('https://example.com');
8-
expect(urlSchema.parse('http://example.com/path')).toBe('http://example.com/path');
9-
});
10-
11-
it('should reject invalid URLs', () => {
12-
expect(() => urlSchema.parse('not a url')).toThrow();
13-
expect(() => urlSchema.parse('example.com')).toThrow();
14-
});
15-
});
16-
17-
describe('dateSchema', () => {
18-
it('should accept valid dates', () => {
19-
expect(dateSchema.parse('2024-01-01')).toBe('2024-01-01');
20-
expect(dateSchema.parse('2024-12-31')).toBe('2024-12-31');
21-
});
22-
23-
it('should reject invalid dates', () => {
24-
expect(() => dateSchema.parse('2024-1-1')).toThrow();
25-
expect(() => dateSchema.parse('01-01-2024')).toThrow();
26-
expect(() => dateSchema.parse('2024/01/01')).toThrow();
27-
});
28-
});
29-
30-
describe('timestampSchema', () => {
31-
it('should accept valid timestamps', () => {
32-
expect(timestampSchema.parse('20240101120000')).toBe('20240101120000');
33-
});
34-
35-
it('should reject invalid timestamps', () => {
36-
expect(() => timestampSchema.parse('2024-01-01')).toThrow();
37-
expect(() => timestampSchema.parse('202401011200')).toThrow();
38-
});
39-
});
5+
describe('urlSchema', () => {
6+
it('should accept valid URLs', () => {
7+
expect(urlSchema.parse('https://example.com')).toBe('https://example.com');
8+
expect(urlSchema.parse('http://example.com/path')).toBe('http://example.com/path');
9+
});
10+
11+
it('should reject invalid URLs', () => {
12+
expect(() => urlSchema.parse('not a url')).toThrow();
13+
expect(() => urlSchema.parse('example.com')).toThrow();
14+
});
15+
});
16+
17+
describe('dateSchema', () => {
18+
it('should accept valid dates', () => {
19+
expect(dateSchema.parse('2024-01-01')).toBe('2024-01-01');
20+
expect(dateSchema.parse('2024-12-31')).toBe('2024-12-31');
21+
});
22+
23+
it('should reject invalid dates', () => {
24+
expect(() => dateSchema.parse('2024-1-1')).toThrow();
25+
expect(() => dateSchema.parse('01-01-2024')).toThrow();
26+
expect(() => dateSchema.parse('2024/01/01')).toThrow();
27+
});
28+
});
29+
30+
describe('timestampSchema', () => {
31+
it('should accept valid timestamps', () => {
32+
expect(timestampSchema.parse('20240101120000')).toBe('20240101120000');
33+
});
34+
35+
it('should reject invalid timestamps', () => {
36+
expect(() => timestampSchema.parse('2024-01-01')).toThrow();
37+
expect(() => timestampSchema.parse('202401011200')).toThrow();
38+
});
39+
});
4040
});
4141

4242
describe('validateInput', () => {
43-
it('should return parsed value for valid input', () => {
44-
const result = validateInput(urlSchema, 'https://example.com');
45-
expect(result).toBe('https://example.com');
46-
});
47-
48-
it('should throw formatted error for invalid input', () => {
49-
expect(() => validateInput(urlSchema, 'invalid')).toThrow('Validation failed');
50-
});
51-
});
43+
it('should return parsed value for valid input', () => {
44+
const result = validateInput(urlSchema, 'https://example.com');
45+
expect(result).toBe('https://example.com');
46+
});
47+
48+
it('should throw formatted error for invalid input', () => {
49+
expect(() => validateInput(urlSchema, 'invalid')).toThrow('Validation failed');
50+
});
51+
});

src/utils/validation.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,26 @@ import { z } from 'zod';
88
export const urlSchema = z.string().url('Invalid URL format');
99

1010
// Date validation
11-
export const dateSchema = z.string().regex(
12-
/^\d{4}-\d{2}-\d{2}$/,
13-
'Date must be in YYYY-MM-DD format'
14-
);
11+
export const dateSchema = z
12+
.string()
13+
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format');
1514

1615
// Timestamp validation (YYYYMMDDHHmmss)
17-
export const timestampSchema = z.string().regex(
18-
/^\d{14}$/,
19-
'Timestamp must be in YYYYMMDDHHmmss format'
20-
);
16+
export const timestampSchema = z
17+
.string()
18+
.regex(/^\d{14}$/, 'Timestamp must be in YYYYMMDDHHmmss format');
2119

2220
/**
2321
* Validate and parse input with helpful error messages
2422
*/
2523
export function validateInput<T>(schema: z.ZodSchema<T>, input: unknown): T {
26-
try {
27-
return schema.parse(input);
28-
} catch (error) {
29-
if (error instanceof z.ZodError) {
30-
const issues = error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}`);
31-
throw new Error(`Validation failed:\n${issues.join('\n')}`);
32-
}
33-
throw error;
34-
}
35-
}
24+
try {
25+
return schema.parse(input);
26+
} catch (error) {
27+
if (error instanceof z.ZodError) {
28+
const issues = error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`);
29+
throw new Error(`Validation failed:\n${issues.join('\n')}`);
30+
}
31+
throw error;
32+
}
33+
}

vitest.config.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,12 @@ export default defineConfig({
55
coverage: {
66
provider: 'v8',
77
reporter: ['text', 'json', 'html', 'lcov'],
8-
exclude: [
9-
'node_modules/',
10-
'dist/',
11-
'**/*.test.ts',
12-
'**/*.d.ts',
13-
'vitest.config.ts',
14-
],
8+
exclude: ['node_modules/', 'dist/', '**/*.test.ts', '**/*.d.ts', 'vitest.config.ts'],
159
all: true,
1610
lines: 80,
1711
functions: 80,
1812
branches: 80,
1913
statements: 80,
2014
},
2115
},
22-
});
16+
});

0 commit comments

Comments
 (0)