@auto-engineer/ai-gateway 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +7 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +21 -0
- package/dist/config.js.map +1 -0
- package/dist/example-use.d.ts +3 -0
- package/dist/example-use.d.ts.map +1 -0
- package/dist/example-use.js +255 -0
- package/dist/example-use.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +351 -0
- package/dist/index.js.map +1 -0
- package/dist/index.specs.d.ts +2 -0
- package/dist/index.specs.d.ts.map +1 -0
- package/dist/index.specs.js +14 -0
- package/dist/index.specs.js.map +1 -0
- package/dist/mcp-server.d.ts +50 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +121 -0
- package/dist/mcp-server.js.map +1 -0
- package/package.json +38 -0
- package/src/config.ts +39 -0
- package/src/example-use.ts +339 -0
- package/src/index.specs.ts +16 -0
- package/src/index.ts +499 -0
- package/src/mcp-server.ts +203 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { registerTool, registerTools, startServer, isServerStarted, type ToolHandler } from '.';
|
|
3
|
+
|
|
4
|
+
// Example 1: Simple tool with basic types
|
|
5
|
+
interface GreetingParams extends Record<string, unknown> {
|
|
6
|
+
name: string;
|
|
7
|
+
language?: 'en' | 'es' | 'fr' | 'de';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
registerTool<GreetingParams>(
|
|
11
|
+
'greet',
|
|
12
|
+
{
|
|
13
|
+
title: 'Greeting Tool',
|
|
14
|
+
description: 'Greets users in different languages',
|
|
15
|
+
inputSchema: {
|
|
16
|
+
name: z.string().min(1, 'Name is required'),
|
|
17
|
+
language: z.enum(['en', 'es', 'fr', 'de']).optional().default('en'),
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
async ({ name, language = 'en' }) => {
|
|
21
|
+
const greetings = {
|
|
22
|
+
en: `Hello, ${name}!`,
|
|
23
|
+
es: `¡Hola, ${name}!`,
|
|
24
|
+
fr: `Bonjour, ${name}!`,
|
|
25
|
+
de: `Hallo, ${name}!`,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
type: 'text' as const,
|
|
32
|
+
text: greetings[language],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Example 2: Calculator tool with validation
|
|
40
|
+
interface CalculatorParams extends Record<string, unknown> {
|
|
41
|
+
operation: 'add' | 'subtract' | 'multiply' | 'divide';
|
|
42
|
+
a: number;
|
|
43
|
+
b: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const calculatorHandler: ToolHandler<CalculatorParams> = async ({ operation, a, b }) => {
|
|
47
|
+
try {
|
|
48
|
+
let result: number;
|
|
49
|
+
|
|
50
|
+
switch (operation) {
|
|
51
|
+
case 'add':
|
|
52
|
+
result = a + b;
|
|
53
|
+
break;
|
|
54
|
+
case 'subtract':
|
|
55
|
+
result = a - b;
|
|
56
|
+
break;
|
|
57
|
+
case 'multiply':
|
|
58
|
+
result = a * b;
|
|
59
|
+
break;
|
|
60
|
+
case 'divide':
|
|
61
|
+
if (b === 0) {
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: 'text' as const,
|
|
66
|
+
text: 'Error: Division by zero',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
result = a / b;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
content: [
|
|
78
|
+
{
|
|
79
|
+
type: 'text' as const,
|
|
80
|
+
text: `${a} ${operation} ${b} = ${result}`,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
} catch (error) {
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: 'text' as const,
|
|
89
|
+
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
isError: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
registerTool<CalculatorParams>(
|
|
98
|
+
'calculator',
|
|
99
|
+
{
|
|
100
|
+
title: 'Calculator',
|
|
101
|
+
description: 'Performs basic arithmetic operations',
|
|
102
|
+
inputSchema: {
|
|
103
|
+
operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
|
|
104
|
+
a: z.number(),
|
|
105
|
+
b: z.number(),
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
calculatorHandler,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Example 3: Batch registration of multiple tools
|
|
112
|
+
interface DateFormatterParams extends Record<string, unknown> {
|
|
113
|
+
date: string;
|
|
114
|
+
format: 'iso' | 'us' | 'eu';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface TextAnalyzerParams extends Record<string, unknown> {
|
|
118
|
+
text: string;
|
|
119
|
+
analysis: 'wordCount' | 'charCount' | 'sentiment';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Register date formatter tool
|
|
123
|
+
registerTool<DateFormatterParams>(
|
|
124
|
+
'dateFormatter',
|
|
125
|
+
{
|
|
126
|
+
title: 'Date Formatter',
|
|
127
|
+
description: 'Formats dates in various styles',
|
|
128
|
+
inputSchema: {
|
|
129
|
+
date: z.string(),
|
|
130
|
+
format: z.enum(['iso', 'us', 'eu']),
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
async ({ date, format }) => {
|
|
134
|
+
const dateObj = new Date(date);
|
|
135
|
+
|
|
136
|
+
if (isNaN(dateObj.getTime())) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: 'text' as const,
|
|
141
|
+
text: 'Invalid date format',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
isError: true,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const formatters = {
|
|
149
|
+
iso: () => dateObj.toISOString(),
|
|
150
|
+
us: () => dateObj.toLocaleDateString('en-US'),
|
|
151
|
+
eu: () => dateObj.toLocaleDateString('en-GB'),
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: 'text' as const,
|
|
158
|
+
text: formatters[format](),
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
// Register text analyzer tool
|
|
166
|
+
registerTool<TextAnalyzerParams>(
|
|
167
|
+
'textAnalyzer',
|
|
168
|
+
{
|
|
169
|
+
title: 'Text Analyzer',
|
|
170
|
+
description: 'Analyzes text content',
|
|
171
|
+
inputSchema: {
|
|
172
|
+
text: z.string(),
|
|
173
|
+
analysis: z.enum(['wordCount', 'charCount', 'sentiment']),
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
async ({ text, analysis }) => {
|
|
177
|
+
const analyzers = {
|
|
178
|
+
wordCount: () => `Word count: ${text.split(/\s+/).filter((w) => w.length > 0).length}`,
|
|
179
|
+
charCount: () => `Character count: ${text.length}`,
|
|
180
|
+
sentiment: () => {
|
|
181
|
+
// Simple sentiment analysis based on keywords
|
|
182
|
+
const positive = ['happy', 'good', 'great', 'excellent', 'wonderful'].some((word) =>
|
|
183
|
+
text.toLowerCase().includes(word),
|
|
184
|
+
);
|
|
185
|
+
const negative = ['sad', 'bad', 'terrible', 'awful', 'horrible'].some((word) =>
|
|
186
|
+
text.toLowerCase().includes(word),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (positive && !negative) return 'Sentiment: Positive 😊';
|
|
190
|
+
if (negative && !positive) return 'Sentiment: Negative 😢';
|
|
191
|
+
if (positive && negative) return 'Sentiment: Mixed 😐';
|
|
192
|
+
return 'Sentiment: Neutral 😐';
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: 'text' as const,
|
|
200
|
+
text: analyzers[analysis](),
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Example 3b: Using registerTools with same parameter types
|
|
208
|
+
interface MathToolParams extends Record<string, unknown> {
|
|
209
|
+
x: number;
|
|
210
|
+
y: number;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
registerTools<MathToolParams>([
|
|
214
|
+
{
|
|
215
|
+
name: 'add',
|
|
216
|
+
description: {
|
|
217
|
+
title: 'Addition',
|
|
218
|
+
description: 'Adds two numbers',
|
|
219
|
+
inputSchema: {
|
|
220
|
+
x: z.number(),
|
|
221
|
+
y: z.number(),
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
handler: async ({ x, y }) => ({
|
|
225
|
+
content: [
|
|
226
|
+
{
|
|
227
|
+
type: 'text' as const,
|
|
228
|
+
text: `${x} + ${y} = ${x + y}`,
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
}),
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: 'multiply',
|
|
235
|
+
description: {
|
|
236
|
+
title: 'Multiplication',
|
|
237
|
+
description: 'Multiplies two numbers',
|
|
238
|
+
inputSchema: {
|
|
239
|
+
x: z.number(),
|
|
240
|
+
y: z.number(),
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
handler: async ({ x, y }) => ({
|
|
244
|
+
content: [
|
|
245
|
+
{
|
|
246
|
+
type: 'text' as const,
|
|
247
|
+
text: `${x} × ${y} = ${x * y}`,
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
}),
|
|
251
|
+
},
|
|
252
|
+
]);
|
|
253
|
+
|
|
254
|
+
// Example 4: Complex tool with nested data
|
|
255
|
+
interface FileManagerParams extends Record<string, unknown> {
|
|
256
|
+
action: 'create' | 'read' | 'list';
|
|
257
|
+
path: string;
|
|
258
|
+
content?: string;
|
|
259
|
+
options?: {
|
|
260
|
+
recursive?: boolean;
|
|
261
|
+
encoding?: 'utf8' | 'base64';
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
registerTool<FileManagerParams>(
|
|
266
|
+
'fileManager',
|
|
267
|
+
{
|
|
268
|
+
title: 'File Manager',
|
|
269
|
+
description: 'Manages files and directories',
|
|
270
|
+
inputSchema: {
|
|
271
|
+
action: z.enum(['create', 'read', 'list']),
|
|
272
|
+
path: z.string(),
|
|
273
|
+
content: z.string().optional(),
|
|
274
|
+
options: z
|
|
275
|
+
.object({
|
|
276
|
+
recursive: z.boolean().optional(),
|
|
277
|
+
encoding: z.enum(['utf8', 'base64']).optional(),
|
|
278
|
+
})
|
|
279
|
+
.optional(),
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
async ({ action, path, content, options }) => {
|
|
283
|
+
// This is a mock implementation for demonstration
|
|
284
|
+
const mockResponses = {
|
|
285
|
+
create: () => `Created file: ${path}`,
|
|
286
|
+
read: () => `Contents of ${path}: ${content ?? '[empty]'}`,
|
|
287
|
+
list: () => `Files in ${path}: file1.txt, file2.txt${options?.recursive === true ? ', subfolder/' : ''}`,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
content: [
|
|
292
|
+
{
|
|
293
|
+
type: 'text' as const,
|
|
294
|
+
text: mockResponses[action](),
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
},
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
// Example usage in an application
|
|
302
|
+
async function main() {
|
|
303
|
+
// Check if server is already started
|
|
304
|
+
if (!isServerStarted()) {
|
|
305
|
+
console.log('Starting MCP server with registered tools...');
|
|
306
|
+
|
|
307
|
+
// You can register more tools here before starting
|
|
308
|
+
registerTool<{ message: string }>(
|
|
309
|
+
'echo',
|
|
310
|
+
{
|
|
311
|
+
title: 'Echo Tool',
|
|
312
|
+
description: 'Echoes back the input message',
|
|
313
|
+
inputSchema: {
|
|
314
|
+
message: z.string(),
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
async ({ message }) => ({
|
|
318
|
+
content: [
|
|
319
|
+
{
|
|
320
|
+
type: 'text' as const,
|
|
321
|
+
text: `Echo: ${message}`,
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
}),
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
// Start the server (this should only be called once in your application)
|
|
328
|
+
await startServer();
|
|
329
|
+
console.log('Server started successfully!');
|
|
330
|
+
} else {
|
|
331
|
+
console.log('Server is already running');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Export for use in other modules
|
|
336
|
+
export { main };
|
|
337
|
+
|
|
338
|
+
// Demonstrate the singleton pattern
|
|
339
|
+
console.log('Example usage loaded. The same server instance will be used across all imports.');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { generateTextWithAI, streamTextWithAI, AIProvider } from './index';
|
|
3
|
+
|
|
4
|
+
describe('AI Integration', () => {
|
|
5
|
+
process.env.OPENAI_API_KEY = 'test';
|
|
6
|
+
|
|
7
|
+
it('should export the correct types', () => {
|
|
8
|
+
expect(typeof generateTextWithAI).toBe('function');
|
|
9
|
+
expect(typeof streamTextWithAI).toBe('function');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should have valid AIProvider type', () => {
|
|
13
|
+
const providers: AIProvider[] = [AIProvider.OpenAI, AIProvider.Anthropic, AIProvider.Google, AIProvider.XAI];
|
|
14
|
+
expect(providers).toContain(AIProvider.OpenAI);
|
|
15
|
+
});
|
|
16
|
+
});
|