@forprompt/sdk 0.1.0

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.
@@ -0,0 +1,2145 @@
1
+ // src/mcp/server.ts
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+
5
+ // src/types.ts
6
+ var ForPromptError = class extends Error {
7
+ constructor(message, statusCode, code) {
8
+ super(message);
9
+ this.statusCode = statusCode;
10
+ this.code = code;
11
+ this.name = "ForPromptError";
12
+ }
13
+ };
14
+
15
+ // src/client.ts
16
+ var DEFAULT_BASE_URL = "https://wooden-fox-811.convex.site";
17
+ var DEFAULT_TIMEOUT = 3e4;
18
+ var DEFAULT_RETRIES = 3;
19
+ function getBackoffDelay(attempt) {
20
+ const baseDelay = Math.pow(2, attempt) * 1e3;
21
+ const jitter = Math.random() * 500;
22
+ return Math.min(baseDelay + jitter, 3e4);
23
+ }
24
+ var ForPrompt = class {
25
+ baseUrl;
26
+ apiKey;
27
+ timeout;
28
+ retries;
29
+ constructor(config) {
30
+ this.apiKey = config.apiKey || "";
31
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
32
+ this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
33
+ this.retries = config.retries ?? DEFAULT_RETRIES;
34
+ }
35
+ /**
36
+ * Fetch with timeout support using AbortController
37
+ */
38
+ async fetchWithTimeout(url, options) {
39
+ const controller = new AbortController();
40
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
41
+ try {
42
+ const response = await fetch(url, {
43
+ ...options,
44
+ signal: controller.signal
45
+ });
46
+ return response;
47
+ } catch (error) {
48
+ if (error instanceof Error && error.name === "AbortError") {
49
+ throw new ForPromptError(
50
+ `Request timeout after ${this.timeout}ms`,
51
+ 408,
52
+ "TIMEOUT"
53
+ );
54
+ }
55
+ throw error;
56
+ } finally {
57
+ clearTimeout(timeoutId);
58
+ }
59
+ }
60
+ /**
61
+ * Fetch with retry and exponential backoff
62
+ */
63
+ async fetchWithRetry(url, options) {
64
+ let lastError = null;
65
+ for (let attempt = 0; attempt < this.retries; attempt++) {
66
+ try {
67
+ const response = await this.fetchWithTimeout(url, options);
68
+ if (response.status >= 400 && response.status < 500) {
69
+ return response;
70
+ }
71
+ if (response.ok) {
72
+ return response;
73
+ }
74
+ lastError = new ForPromptError(
75
+ `Server error: ${response.status}`,
76
+ response.status,
77
+ "SERVER_ERROR"
78
+ );
79
+ } catch (error) {
80
+ lastError = error instanceof Error ? error : new Error(String(error));
81
+ if (error instanceof ForPromptError && error.code === "TIMEOUT") {
82
+ throw error;
83
+ }
84
+ }
85
+ if (attempt < this.retries - 1) {
86
+ const delay = getBackoffDelay(attempt);
87
+ await new Promise((resolve) => setTimeout(resolve, delay));
88
+ }
89
+ }
90
+ throw lastError || new ForPromptError(
91
+ "Request failed after retries",
92
+ 500,
93
+ "RETRY_EXHAUSTED"
94
+ );
95
+ }
96
+ /**
97
+ * Get a prompt by its key
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const prompt = await forprompt.getPrompt("userContextPrompt");
102
+ * console.log(prompt.systemPrompt);
103
+ * ```
104
+ *
105
+ * @example With specific version
106
+ * ```typescript
107
+ * const prompt = await forprompt.getPrompt("userContextPrompt", { version: 2 });
108
+ * ```
109
+ */
110
+ async getPrompt(key, options) {
111
+ if (!this.apiKey) {
112
+ throw new ForPromptError(
113
+ "API key is required. Set FORPROMPT_API_KEY environment variable or pass apiKey in config.",
114
+ 401,
115
+ "MISSING_API_KEY"
116
+ );
117
+ }
118
+ if (!key || typeof key !== "string") {
119
+ throw new ForPromptError(
120
+ "Prompt key must be a non-empty string",
121
+ 400,
122
+ "INVALID_INPUT"
123
+ );
124
+ }
125
+ if (key.length > 256) {
126
+ throw new ForPromptError(
127
+ "Prompt key must be 256 characters or less",
128
+ 400,
129
+ "INVALID_INPUT"
130
+ );
131
+ }
132
+ if (options?.version !== void 0) {
133
+ if (!Number.isInteger(options.version) || options.version < 1) {
134
+ throw new ForPromptError(
135
+ "Version must be a positive integer",
136
+ 400,
137
+ "INVALID_INPUT"
138
+ );
139
+ }
140
+ }
141
+ const url = new URL(`${this.baseUrl}/api/prompts`);
142
+ url.searchParams.set("key", key);
143
+ if (options?.version !== void 0) {
144
+ url.searchParams.set("version", String(options.version));
145
+ }
146
+ const response = await this.fetchWithRetry(url.toString(), {
147
+ method: "GET",
148
+ headers: {
149
+ "Content-Type": "application/json",
150
+ "X-API-Key": this.apiKey
151
+ }
152
+ });
153
+ if (!response.ok) {
154
+ const errorData = await response.json().catch(() => ({ error: "Unknown error" }));
155
+ throw new ForPromptError(
156
+ errorData.error || `Failed to fetch prompt: ${key}`,
157
+ response.status,
158
+ response.status === 404 ? "PROMPT_NOT_FOUND" : "API_ERROR"
159
+ );
160
+ }
161
+ return response.json();
162
+ }
163
+ /**
164
+ * Get multiple prompts by their keys
165
+ *
166
+ * Requests are made in parallel with concurrency limit to avoid overwhelming the server.
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * const prompts = await forprompt.getPrompts(["userContext", "chatDefault"]);
171
+ * ```
172
+ */
173
+ async getPrompts(keys, options) {
174
+ const CONCURRENCY_LIMIT = 5;
175
+ const promptMap = /* @__PURE__ */ new Map();
176
+ for (let i = 0; i < keys.length; i += CONCURRENCY_LIMIT) {
177
+ const batch = keys.slice(i, i + CONCURRENCY_LIMIT);
178
+ const results = await Promise.allSettled(
179
+ batch.map((key) => this.getPrompt(key, options))
180
+ );
181
+ results.forEach((result, index) => {
182
+ if (result.status === "fulfilled") {
183
+ promptMap.set(batch[index], result.value);
184
+ }
185
+ });
186
+ }
187
+ return promptMap;
188
+ }
189
+ };
190
+ function createForPrompt(config) {
191
+ const apiKey = config?.apiKey || process.env.FORPROMPT_API_KEY || "";
192
+ const baseUrl = config?.baseUrl || process.env.FORPROMPT_BASE_URL;
193
+ return new ForPrompt({
194
+ apiKey,
195
+ baseUrl,
196
+ timeout: config?.timeout,
197
+ retries: config?.retries
198
+ });
199
+ }
200
+ var forprompt = createForPrompt();
201
+
202
+ // src/mcp/tools.ts
203
+ import { z } from "zod";
204
+ var DEFAULT_BASE_URL2 = "https://wooden-fox-811.convex.site";
205
+ function getApiConfig(config) {
206
+ const apiKey = config.apiKey || process.env.FORPROMPT_API_KEY;
207
+ const baseUrl = (config.baseUrl || process.env.FORPROMPT_BASE_URL || DEFAULT_BASE_URL2).replace(/\/$/, "");
208
+ if (!apiKey) {
209
+ throw new Error(
210
+ "API key is required. Set FORPROMPT_API_KEY environment variable."
211
+ );
212
+ }
213
+ return { apiKey, baseUrl };
214
+ }
215
+ async function fetchAllPrompts(config) {
216
+ const { apiKey, baseUrl } = getApiConfig(config);
217
+ const response = await fetch(`${baseUrl}/api/sync`, {
218
+ method: "GET",
219
+ headers: {
220
+ "Content-Type": "application/json",
221
+ "X-API-Key": apiKey
222
+ }
223
+ });
224
+ if (!response.ok) {
225
+ const errorData = await response.json().catch(() => ({
226
+ error: "Unknown error"
227
+ }));
228
+ throw new Error(errorData.error || `Failed to fetch prompts`);
229
+ }
230
+ const data = await response.json();
231
+ return data.prompts;
232
+ }
233
+ async function createPrompt(config, data) {
234
+ const { apiKey, baseUrl } = getApiConfig(config);
235
+ const response = await fetch(`${baseUrl}/api/prompts`, {
236
+ method: "POST",
237
+ headers: {
238
+ "Content-Type": "application/json",
239
+ "X-API-Key": apiKey
240
+ },
241
+ body: JSON.stringify(data)
242
+ });
243
+ if (!response.ok) {
244
+ const errorData = await response.json().catch(() => ({
245
+ error: "Unknown error"
246
+ }));
247
+ throw new Error(errorData.error || "Failed to create prompt");
248
+ }
249
+ return response.json();
250
+ }
251
+ async function updatePrompt(config, data) {
252
+ const { apiKey, baseUrl } = getApiConfig(config);
253
+ const response = await fetch(`${baseUrl}/api/prompts`, {
254
+ method: "PUT",
255
+ headers: {
256
+ "Content-Type": "application/json",
257
+ "X-API-Key": apiKey
258
+ },
259
+ body: JSON.stringify(data)
260
+ });
261
+ if (!response.ok) {
262
+ const errorData = await response.json().catch(() => ({
263
+ error: "Unknown error"
264
+ }));
265
+ throw new Error(errorData.error || "Failed to update prompt");
266
+ }
267
+ return response.json();
268
+ }
269
+ async function createVersionApi(config, data) {
270
+ const { apiKey, baseUrl } = getApiConfig(config);
271
+ const response = await fetch(`${baseUrl}/api/prompts/versions`, {
272
+ method: "POST",
273
+ headers: {
274
+ "Content-Type": "application/json",
275
+ "X-API-Key": apiKey
276
+ },
277
+ body: JSON.stringify(data)
278
+ });
279
+ if (!response.ok) {
280
+ const errorData = await response.json().catch(() => ({
281
+ error: "Unknown error"
282
+ }));
283
+ throw new Error(errorData.error || "Failed to create version");
284
+ }
285
+ return response.json();
286
+ }
287
+ async function deletePromptApi(config, key) {
288
+ const { apiKey, baseUrl } = getApiConfig(config);
289
+ const response = await fetch(`${baseUrl}/api/prompts?key=${encodeURIComponent(key)}`, {
290
+ method: "DELETE",
291
+ headers: {
292
+ "Content-Type": "application/json",
293
+ "X-API-Key": apiKey
294
+ }
295
+ });
296
+ if (!response.ok) {
297
+ const errorData = await response.json().catch(() => ({
298
+ error: "Unknown error"
299
+ }));
300
+ throw new Error(errorData.error || "Failed to delete prompt");
301
+ }
302
+ return response.json();
303
+ }
304
+ function formatPrompt(prompt) {
305
+ const sections = [];
306
+ sections.push(`# ${prompt.name}`);
307
+ sections.push(`**Key:** ${prompt.key}`);
308
+ sections.push(`**Version:** ${prompt.versionNumber}`);
309
+ if (prompt.description) {
310
+ sections.push(`**Description:** ${prompt.description}`);
311
+ }
312
+ sections.push("");
313
+ sections.push("## System Prompt");
314
+ sections.push("```");
315
+ sections.push(prompt.systemPrompt);
316
+ sections.push("```");
317
+ if (prompt.purpose) {
318
+ sections.push("");
319
+ sections.push("## Purpose");
320
+ sections.push(prompt.purpose);
321
+ }
322
+ if (prompt.expectedBehavior) {
323
+ sections.push("");
324
+ sections.push("## Expected Behavior");
325
+ sections.push(prompt.expectedBehavior);
326
+ }
327
+ if (prompt.inputFormat) {
328
+ sections.push("");
329
+ sections.push("## Input Format");
330
+ sections.push(prompt.inputFormat);
331
+ }
332
+ if (prompt.outputFormat) {
333
+ sections.push("");
334
+ sections.push("## Output Format");
335
+ sections.push(prompt.outputFormat);
336
+ }
337
+ if (prompt.constraints) {
338
+ sections.push("");
339
+ sections.push("## Constraints");
340
+ sections.push(prompt.constraints);
341
+ }
342
+ if (prompt.useCases) {
343
+ sections.push("");
344
+ sections.push("## Use Cases");
345
+ sections.push(prompt.useCases);
346
+ }
347
+ if (prompt.additionalNotes) {
348
+ sections.push("");
349
+ sections.push("## Additional Notes");
350
+ sections.push(prompt.additionalNotes);
351
+ }
352
+ if (prompt.toolsNotes) {
353
+ sections.push("");
354
+ sections.push("## Tools Notes");
355
+ sections.push(prompt.toolsNotes);
356
+ }
357
+ return sections.join("\n");
358
+ }
359
+ var GetPromptInputSchema = z.object({
360
+ key: z.string().describe("The unique key identifier for the prompt"),
361
+ version: z.number().optional().describe(
362
+ "Specific version number to fetch (optional, defaults to active version)"
363
+ )
364
+ });
365
+ var ListPromptsInputSchema = z.object({
366
+ search: z.string().optional().describe("Optional search term to filter prompts by name or key")
367
+ });
368
+ var SearchPromptsInputSchema = z.object({
369
+ query: z.string().describe("Search query to find matching prompts")
370
+ });
371
+ var GetMetadataInputSchema = z.object({
372
+ key: z.string().describe("The unique key identifier for the prompt")
373
+ });
374
+ var GetSystemPromptInputSchema = z.object({
375
+ key: z.string().describe("The unique key identifier for the prompt"),
376
+ version: z.number().optional().describe("Specific version number (optional)")
377
+ });
378
+ var CreatePromptInputSchema = z.object({
379
+ key: z.string().describe(
380
+ "Unique key identifier for the prompt (lowercase, no spaces, use underscores)"
381
+ ),
382
+ name: z.string().describe("Human-readable name for the prompt"),
383
+ description: z.string().optional().describe("Description of what the prompt does"),
384
+ systemPrompt: z.string().optional().describe("Initial system prompt content (optional, can be added later)")
385
+ });
386
+ var UpdatePromptInputSchema = z.object({
387
+ key: z.string().describe("The unique key identifier for the prompt to update"),
388
+ name: z.string().optional().describe("New name for the prompt"),
389
+ description: z.string().optional().describe("New description"),
390
+ purpose: z.string().optional().describe("The purpose/goal of this prompt"),
391
+ expectedBehavior: z.string().optional().describe("Expected behavior when using this prompt"),
392
+ inputFormat: z.string().optional().describe("Expected input format"),
393
+ outputFormat: z.string().optional().describe("Expected output format"),
394
+ constraints: z.string().optional().describe("Constraints and limitations"),
395
+ useCases: z.string().optional().describe("Primary use cases"),
396
+ additionalNotes: z.string().optional().describe("Additional notes"),
397
+ toolsNotes: z.string().optional().describe("Notes about tool usage")
398
+ });
399
+ var CreateVersionInputSchema = z.object({
400
+ key: z.string().describe("The prompt key to create a new version for"),
401
+ systemPrompt: z.string().describe("The new system prompt content"),
402
+ description: z.string().optional().describe("Description of changes in this version"),
403
+ setAsActive: z.boolean().optional().describe("Whether to set this as the active version (default: true)")
404
+ });
405
+ var DeletePromptInputSchema = z.object({
406
+ key: z.string().describe("The unique key identifier for the prompt to delete")
407
+ });
408
+ var SetupProjectInputSchema = z.object({
409
+ projectPath: z.string().describe("Absolute path to the project root directory"),
410
+ language: z.enum(["typescript", "javascript", "python"]).optional().describe("Programming language (auto-detected if not specified)"),
411
+ packageManager: z.enum(["npm", "yarn", "pnpm", "bun", "pip", "poetry", "uv"]).optional().describe("Package manager to use (auto-detected if not specified)")
412
+ });
413
+ var GenerateConfigInputSchema = z.object({
414
+ projectPath: z.string().describe("Absolute path to the project root directory"),
415
+ apiKey: z.string().optional().describe("API key (will prompt user if not provided)"),
416
+ baseUrl: z.string().optional().describe("Custom API base URL (optional)")
417
+ });
418
+ var GenerateExampleInputSchema = z.object({
419
+ language: z.enum(["typescript", "javascript", "python"]).describe("Programming language for the example"),
420
+ useCase: z.enum(["basic", "streaming", "with-tools", "react-hook", "nextjs-api"]).describe("Type of example to generate"),
421
+ promptKey: z.string().optional().describe("Optional prompt key to use in the example")
422
+ });
423
+ var DetectProjectInputSchema = z.object({
424
+ projectPath: z.string().describe("Absolute path to the project root directory")
425
+ });
426
+ var GetIntegrationGuideInputSchema = z.object({
427
+ framework: z.enum(["nextjs", "react", "express", "fastapi", "django", "flask", "generic"]).describe("Framework to get integration guide for"),
428
+ language: z.enum(["typescript", "javascript", "python"]).optional().describe("Programming language")
429
+ });
430
+ function registerTools(server, client, config) {
431
+ server.registerTool(
432
+ "forprompt_get_prompt",
433
+ {
434
+ description: "Fetch a prompt by its key from ForPrompt. Returns the system prompt content and metadata including purpose, expected behavior, constraints, and more.",
435
+ inputSchema: GetPromptInputSchema
436
+ },
437
+ async ({ key, version }) => {
438
+ try {
439
+ const prompt = await client.getPrompt(key, { version });
440
+ return {
441
+ content: [
442
+ {
443
+ type: "text",
444
+ text: formatPrompt(prompt)
445
+ }
446
+ ]
447
+ };
448
+ } catch (error) {
449
+ const message = error instanceof Error ? error.message : "Unknown error";
450
+ return {
451
+ content: [
452
+ {
453
+ type: "text",
454
+ text: `Error fetching prompt "${key}": ${message}`
455
+ }
456
+ ],
457
+ isError: true
458
+ };
459
+ }
460
+ }
461
+ );
462
+ server.registerTool(
463
+ "forprompt_list_prompts",
464
+ {
465
+ description: "List all available prompts in your ForPrompt project. Returns a summary of each prompt including key, name, description, and version.",
466
+ inputSchema: ListPromptsInputSchema
467
+ },
468
+ async ({ search }) => {
469
+ try {
470
+ let prompts = await fetchAllPrompts(config);
471
+ if (search) {
472
+ const searchLower = search.toLowerCase();
473
+ prompts = prompts.filter(
474
+ (p) => p.key.toLowerCase().includes(searchLower) || p.name.toLowerCase().includes(searchLower) || p.description?.toLowerCase().includes(searchLower)
475
+ );
476
+ }
477
+ if (prompts.length === 0) {
478
+ return {
479
+ content: [
480
+ {
481
+ type: "text",
482
+ text: search ? `No prompts found matching "${search}"` : "No prompts found in this project"
483
+ }
484
+ ]
485
+ };
486
+ }
487
+ const lines = prompts.map((p) => {
488
+ const desc = p.description ? ` - ${p.description}` : "";
489
+ return `- **${p.key}** (v${p.versionNumber}): ${p.name}${desc}`;
490
+ });
491
+ return {
492
+ content: [
493
+ {
494
+ type: "text",
495
+ text: `# ForPrompt Prompts
496
+
497
+ Found ${prompts.length} prompt(s):
498
+
499
+ ${lines.join("\n")}`
500
+ }
501
+ ]
502
+ };
503
+ } catch (error) {
504
+ const message = error instanceof Error ? error.message : "Unknown error";
505
+ return {
506
+ content: [
507
+ {
508
+ type: "text",
509
+ text: `Error listing prompts: ${message}`
510
+ }
511
+ ],
512
+ isError: true
513
+ };
514
+ }
515
+ }
516
+ );
517
+ server.registerTool(
518
+ "forprompt_search_prompts",
519
+ {
520
+ description: "Search prompts by text query. Searches across prompt names, keys, descriptions, purposes, and use cases.",
521
+ inputSchema: SearchPromptsInputSchema
522
+ },
523
+ async ({ query }) => {
524
+ try {
525
+ const allPrompts = await fetchAllPrompts(config);
526
+ const queryLower = query.toLowerCase();
527
+ const matches = allPrompts.filter((p) => {
528
+ const searchFields = [
529
+ p.key,
530
+ p.name,
531
+ p.description,
532
+ p.purpose,
533
+ p.useCases,
534
+ p.expectedBehavior,
535
+ p.systemPrompt
536
+ ];
537
+ return searchFields.some(
538
+ (field) => field && field.toLowerCase().includes(queryLower)
539
+ );
540
+ });
541
+ if (matches.length === 0) {
542
+ return {
543
+ content: [
544
+ {
545
+ type: "text",
546
+ text: `No prompts found matching "${query}"`
547
+ }
548
+ ]
549
+ };
550
+ }
551
+ const results = matches.map((p) => {
552
+ const sections = [`## ${p.name} (\`${p.key}\`)`];
553
+ if (p.description) sections.push(`*${p.description}*`);
554
+ sections.push(`Version: ${p.versionNumber}`);
555
+ if (p.purpose) sections.push(`**Purpose:** ${p.purpose}`);
556
+ return sections.join("\n");
557
+ });
558
+ return {
559
+ content: [
560
+ {
561
+ type: "text",
562
+ text: `# Search Results for "${query}"
563
+
564
+ Found ${matches.length} matching prompt(s):
565
+
566
+ ${results.join("\n\n---\n\n")}`
567
+ }
568
+ ]
569
+ };
570
+ } catch (error) {
571
+ const message = error instanceof Error ? error.message : "Unknown error";
572
+ return {
573
+ content: [
574
+ {
575
+ type: "text",
576
+ text: `Error searching prompts: ${message}`
577
+ }
578
+ ],
579
+ isError: true
580
+ };
581
+ }
582
+ }
583
+ );
584
+ server.registerTool(
585
+ "forprompt_get_prompt_metadata",
586
+ {
587
+ description: "Get metadata for a prompt without the full system prompt content. Useful for understanding what a prompt does before fetching it.",
588
+ inputSchema: GetMetadataInputSchema
589
+ },
590
+ async ({ key }) => {
591
+ try {
592
+ const prompt = await client.getPrompt(key);
593
+ const metadata = {
594
+ key: prompt.key,
595
+ name: prompt.name,
596
+ description: prompt.description,
597
+ versionNumber: prompt.versionNumber,
598
+ updatedAt: new Date(prompt.updatedAt).toISOString(),
599
+ purpose: prompt.purpose,
600
+ expectedBehavior: prompt.expectedBehavior,
601
+ inputFormat: prompt.inputFormat,
602
+ outputFormat: prompt.outputFormat,
603
+ constraints: prompt.constraints,
604
+ useCases: prompt.useCases,
605
+ additionalNotes: prompt.additionalNotes,
606
+ toolsNotes: prompt.toolsNotes,
607
+ systemPromptLength: prompt.systemPrompt.length
608
+ };
609
+ return {
610
+ content: [
611
+ {
612
+ type: "text",
613
+ text: `# Metadata for "${prompt.name}"
614
+
615
+ \`\`\`json
616
+ ${JSON.stringify(metadata, null, 2)}
617
+ \`\`\``
618
+ }
619
+ ]
620
+ };
621
+ } catch (error) {
622
+ const message = error instanceof Error ? error.message : "Unknown error";
623
+ return {
624
+ content: [
625
+ {
626
+ type: "text",
627
+ text: `Error fetching metadata for "${key}": ${message}`
628
+ }
629
+ ],
630
+ isError: true
631
+ };
632
+ }
633
+ }
634
+ );
635
+ server.registerTool(
636
+ "forprompt_get_system_prompt",
637
+ {
638
+ description: "Get only the raw system prompt text without metadata. Useful when you just need the prompt content to use directly.",
639
+ inputSchema: GetSystemPromptInputSchema
640
+ },
641
+ async ({ key, version }) => {
642
+ try {
643
+ const prompt = await client.getPrompt(key, { version });
644
+ return {
645
+ content: [
646
+ {
647
+ type: "text",
648
+ text: prompt.systemPrompt
649
+ }
650
+ ]
651
+ };
652
+ } catch (error) {
653
+ const message = error instanceof Error ? error.message : "Unknown error";
654
+ return {
655
+ content: [
656
+ {
657
+ type: "text",
658
+ text: `Error fetching system prompt for "${key}": ${message}`
659
+ }
660
+ ],
661
+ isError: true
662
+ };
663
+ }
664
+ }
665
+ );
666
+ server.registerTool(
667
+ "forprompt_create_prompt",
668
+ {
669
+ description: "Create a new prompt in ForPrompt. You can optionally include an initial system prompt content. The key must be unique, lowercase, and use underscores instead of spaces.",
670
+ inputSchema: CreatePromptInputSchema
671
+ },
672
+ async ({ key, name, description, systemPrompt }) => {
673
+ try {
674
+ const result = await createPrompt(config, {
675
+ key,
676
+ name,
677
+ description,
678
+ systemPrompt
679
+ });
680
+ let message = `Successfully created prompt "${name}" with key "${key}"`;
681
+ if (result.versionNumber) {
682
+ message += ` (v${result.versionNumber})`;
683
+ }
684
+ return {
685
+ content: [
686
+ {
687
+ type: "text",
688
+ text: message
689
+ }
690
+ ]
691
+ };
692
+ } catch (error) {
693
+ const message = error instanceof Error ? error.message : "Unknown error";
694
+ return {
695
+ content: [
696
+ {
697
+ type: "text",
698
+ text: `Error creating prompt: ${message}`
699
+ }
700
+ ],
701
+ isError: true
702
+ };
703
+ }
704
+ }
705
+ );
706
+ server.registerTool(
707
+ "forprompt_update_prompt",
708
+ {
709
+ description: "Update an existing prompt's metadata (name, description, purpose, expected behavior, etc.). To update the system prompt content, use forprompt_create_version instead.",
710
+ inputSchema: UpdatePromptInputSchema
711
+ },
712
+ async (args) => {
713
+ try {
714
+ await updatePrompt(config, args);
715
+ return {
716
+ content: [
717
+ {
718
+ type: "text",
719
+ text: `Successfully updated prompt "${args.key}"`
720
+ }
721
+ ]
722
+ };
723
+ } catch (error) {
724
+ const message = error instanceof Error ? error.message : "Unknown error";
725
+ return {
726
+ content: [
727
+ {
728
+ type: "text",
729
+ text: `Error updating prompt: ${message}`
730
+ }
731
+ ],
732
+ isError: true
733
+ };
734
+ }
735
+ }
736
+ );
737
+ server.registerTool(
738
+ "forprompt_create_version",
739
+ {
740
+ description: "Create a new version of an existing prompt with updated system prompt content. This is the proper way to update the actual prompt text while maintaining version history.",
741
+ inputSchema: CreateVersionInputSchema
742
+ },
743
+ async ({ key, systemPrompt, description, setAsActive }) => {
744
+ try {
745
+ const result = await createVersionApi(config, {
746
+ key,
747
+ systemPrompt,
748
+ description,
749
+ setAsActive
750
+ });
751
+ return {
752
+ content: [
753
+ {
754
+ type: "text",
755
+ text: `Successfully created version ${result.versionNumber} for prompt "${key}"`
756
+ }
757
+ ]
758
+ };
759
+ } catch (error) {
760
+ const message = error instanceof Error ? error.message : "Unknown error";
761
+ return {
762
+ content: [
763
+ {
764
+ type: "text",
765
+ text: `Error creating version: ${message}`
766
+ }
767
+ ],
768
+ isError: true
769
+ };
770
+ }
771
+ }
772
+ );
773
+ server.registerTool(
774
+ "forprompt_delete_prompt",
775
+ {
776
+ description: "Delete a prompt and all its versions. This action is irreversible. Use with caution.",
777
+ inputSchema: DeletePromptInputSchema
778
+ },
779
+ async ({ key }) => {
780
+ try {
781
+ await deletePromptApi(config, key);
782
+ return {
783
+ content: [
784
+ {
785
+ type: "text",
786
+ text: `Successfully deleted prompt "${key}" and all its versions`
787
+ }
788
+ ]
789
+ };
790
+ } catch (error) {
791
+ const message = error instanceof Error ? error.message : "Unknown error";
792
+ return {
793
+ content: [
794
+ {
795
+ type: "text",
796
+ text: `Error deleting prompt: ${message}`
797
+ }
798
+ ],
799
+ isError: true
800
+ };
801
+ }
802
+ }
803
+ );
804
+ server.registerTool(
805
+ "forprompt_detect_project",
806
+ {
807
+ description: "Detect the project type, language, and package manager in a directory. Use this first before running setup to understand the project structure.",
808
+ inputSchema: DetectProjectInputSchema
809
+ },
810
+ async ({ projectPath }) => {
811
+ try {
812
+ const fs = await import("fs");
813
+ const path = await import("path");
814
+ const detection = {
815
+ language: null,
816
+ packageManager: null,
817
+ framework: null,
818
+ hasForPrompt: false,
819
+ configFiles: []
820
+ };
821
+ const packageJsonPath = path.join(projectPath, "package.json");
822
+ if (fs.existsSync(packageJsonPath)) {
823
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
824
+ if (packageJson.devDependencies?.typescript || packageJson.dependencies?.typescript) {
825
+ detection.language = "typescript";
826
+ } else {
827
+ detection.language = "javascript";
828
+ }
829
+ if (packageJson.dependencies?.["@forprompt/sdk"] || packageJson.devDependencies?.["@forprompt/sdk"]) {
830
+ detection.hasForPrompt = true;
831
+ }
832
+ if (packageJson.dependencies?.next) {
833
+ detection.framework = "nextjs";
834
+ } else if (packageJson.dependencies?.react) {
835
+ detection.framework = "react";
836
+ } else if (packageJson.dependencies?.express) {
837
+ detection.framework = "express";
838
+ }
839
+ if (fs.existsSync(path.join(projectPath, "pnpm-lock.yaml"))) {
840
+ detection.packageManager = "pnpm";
841
+ } else if (fs.existsSync(path.join(projectPath, "yarn.lock"))) {
842
+ detection.packageManager = "yarn";
843
+ } else if (fs.existsSync(path.join(projectPath, "bun.lockb"))) {
844
+ detection.packageManager = "bun";
845
+ } else if (fs.existsSync(path.join(projectPath, "package-lock.json"))) {
846
+ detection.packageManager = "npm";
847
+ }
848
+ detection.configFiles.push("package.json");
849
+ }
850
+ const pyprojectPath = path.join(projectPath, "pyproject.toml");
851
+ const requirementsPath = path.join(projectPath, "requirements.txt");
852
+ if (fs.existsSync(pyprojectPath)) {
853
+ detection.language = "python";
854
+ const content = fs.readFileSync(pyprojectPath, "utf-8");
855
+ if (content.includes("poetry")) {
856
+ detection.packageManager = "poetry";
857
+ } else if (content.includes("uv")) {
858
+ detection.packageManager = "uv";
859
+ } else {
860
+ detection.packageManager = "pip";
861
+ }
862
+ detection.configFiles.push("pyproject.toml");
863
+ if (content.includes("fastapi")) {
864
+ detection.framework = "fastapi";
865
+ } else if (content.includes("django")) {
866
+ detection.framework = "django";
867
+ } else if (content.includes("flask")) {
868
+ detection.framework = "flask";
869
+ }
870
+ if (content.includes("forprompt")) {
871
+ detection.hasForPrompt = true;
872
+ }
873
+ } else if (fs.existsSync(requirementsPath)) {
874
+ detection.language = "python";
875
+ detection.packageManager = "pip";
876
+ detection.configFiles.push("requirements.txt");
877
+ const content = fs.readFileSync(requirementsPath, "utf-8");
878
+ if (content.includes("forprompt")) {
879
+ detection.hasForPrompt = true;
880
+ }
881
+ }
882
+ const forpromptConfigPath = path.join(projectPath, ".forprompt");
883
+ if (fs.existsSync(forpromptConfigPath)) {
884
+ detection.configFiles.push(".forprompt");
885
+ }
886
+ if (!detection.language) {
887
+ return {
888
+ content: [
889
+ {
890
+ type: "text",
891
+ text: `Could not detect project type at "${projectPath}". Make sure the path contains a package.json (Node.js) or pyproject.toml/requirements.txt (Python).`
892
+ }
893
+ ],
894
+ isError: true
895
+ };
896
+ }
897
+ const lines = [
898
+ `# Project Detection Results`,
899
+ ``,
900
+ `**Path:** ${projectPath}`,
901
+ `**Language:** ${detection.language}`,
902
+ `**Package Manager:** ${detection.packageManager || "unknown"}`,
903
+ `**Framework:** ${detection.framework || "none detected"}`,
904
+ `**ForPrompt Installed:** ${detection.hasForPrompt ? "Yes" : "No"}`,
905
+ `**Config Files Found:** ${detection.configFiles.join(", ")}`,
906
+ ``
907
+ ];
908
+ if (!detection.hasForPrompt) {
909
+ lines.push(`## Next Steps`);
910
+ lines.push(``);
911
+ lines.push(`1. Run \`forprompt_setup_project\` to install the SDK`);
912
+ lines.push(`2. Run \`forprompt_generate_config\` to create the config file`);
913
+ lines.push(`3. Use \`forprompt_generate_example\` to see usage examples`);
914
+ } else {
915
+ lines.push(`ForPrompt is already installed! You can:`);
916
+ lines.push(`- Use \`forprompt_list_prompts\` to see available prompts`);
917
+ lines.push(`- Use \`forprompt_create_prompt\` to create new prompts`);
918
+ }
919
+ return {
920
+ content: [
921
+ {
922
+ type: "text",
923
+ text: lines.join("\n")
924
+ }
925
+ ]
926
+ };
927
+ } catch (error) {
928
+ const message = error instanceof Error ? error.message : "Unknown error";
929
+ return {
930
+ content: [
931
+ {
932
+ type: "text",
933
+ text: `Error detecting project: ${message}`
934
+ }
935
+ ],
936
+ isError: true
937
+ };
938
+ }
939
+ }
940
+ );
941
+ server.registerTool(
942
+ "forprompt_setup_project",
943
+ {
944
+ description: "Install the ForPrompt SDK in a project. Auto-detects the language and package manager, or you can specify them. Returns the command to run - you should execute it using your terminal/bash tool.",
945
+ inputSchema: SetupProjectInputSchema
946
+ },
947
+ async ({ projectPath, language, packageManager }) => {
948
+ try {
949
+ const fs = await import("fs");
950
+ const path = await import("path");
951
+ let detectedLanguage = language;
952
+ let detectedPM = packageManager;
953
+ if (!detectedLanguage || !detectedPM) {
954
+ const packageJsonPath = path.join(projectPath, "package.json");
955
+ const pyprojectPath = path.join(projectPath, "pyproject.toml");
956
+ const requirementsPath = path.join(projectPath, "requirements.txt");
957
+ if (fs.existsSync(packageJsonPath)) {
958
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
959
+ if (!detectedLanguage) {
960
+ detectedLanguage = packageJson.devDependencies?.typescript ? "typescript" : "javascript";
961
+ }
962
+ if (!detectedPM) {
963
+ if (fs.existsSync(path.join(projectPath, "pnpm-lock.yaml"))) {
964
+ detectedPM = "pnpm";
965
+ } else if (fs.existsSync(path.join(projectPath, "yarn.lock"))) {
966
+ detectedPM = "yarn";
967
+ } else if (fs.existsSync(path.join(projectPath, "bun.lockb"))) {
968
+ detectedPM = "bun";
969
+ } else {
970
+ detectedPM = "npm";
971
+ }
972
+ }
973
+ } else if (fs.existsSync(pyprojectPath) || fs.existsSync(requirementsPath)) {
974
+ detectedLanguage = "python";
975
+ if (!detectedPM) {
976
+ if (fs.existsSync(pyprojectPath)) {
977
+ const content = fs.readFileSync(pyprojectPath, "utf-8");
978
+ if (content.includes("poetry")) {
979
+ detectedPM = "poetry";
980
+ } else {
981
+ detectedPM = "pip";
982
+ }
983
+ } else {
984
+ detectedPM = "pip";
985
+ }
986
+ }
987
+ }
988
+ }
989
+ if (!detectedLanguage) {
990
+ return {
991
+ content: [
992
+ {
993
+ type: "text",
994
+ text: `Could not detect project type. Please specify the language parameter ("typescript", "javascript", or "python").`
995
+ }
996
+ ],
997
+ isError: true
998
+ };
999
+ }
1000
+ let installCommand;
1001
+ let packageName;
1002
+ if (detectedLanguage === "python") {
1003
+ packageName = "forprompt";
1004
+ switch (detectedPM) {
1005
+ case "poetry":
1006
+ installCommand = `cd "${projectPath}" && poetry add ${packageName}`;
1007
+ break;
1008
+ case "uv":
1009
+ installCommand = `cd "${projectPath}" && uv add ${packageName}`;
1010
+ break;
1011
+ default:
1012
+ installCommand = `cd "${projectPath}" && pip install ${packageName}`;
1013
+ }
1014
+ } else {
1015
+ packageName = "@forprompt/sdk";
1016
+ switch (detectedPM) {
1017
+ case "yarn":
1018
+ installCommand = `cd "${projectPath}" && yarn add ${packageName}`;
1019
+ break;
1020
+ case "pnpm":
1021
+ installCommand = `cd "${projectPath}" && pnpm add ${packageName}`;
1022
+ break;
1023
+ case "bun":
1024
+ installCommand = `cd "${projectPath}" && bun add ${packageName}`;
1025
+ break;
1026
+ default:
1027
+ installCommand = `cd "${projectPath}" && npm install ${packageName}`;
1028
+ }
1029
+ }
1030
+ const lines = [
1031
+ `# ForPrompt SDK Installation`,
1032
+ ``,
1033
+ `**Project:** ${projectPath}`,
1034
+ `**Language:** ${detectedLanguage}`,
1035
+ `**Package Manager:** ${detectedPM}`,
1036
+ ``,
1037
+ `## Install Command`,
1038
+ ``,
1039
+ "```bash",
1040
+ installCommand,
1041
+ "```",
1042
+ ``,
1043
+ `**Run this command to install the ForPrompt SDK.**`,
1044
+ ``,
1045
+ `## After Installation`,
1046
+ ``,
1047
+ `1. Create a \`.forprompt\` config file with your API key`,
1048
+ `2. Or set the \`FORPROMPT_API_KEY\` environment variable`,
1049
+ ``,
1050
+ `Use \`forprompt_generate_config\` to create the config file automatically.`
1051
+ ];
1052
+ return {
1053
+ content: [
1054
+ {
1055
+ type: "text",
1056
+ text: lines.join("\n")
1057
+ }
1058
+ ]
1059
+ };
1060
+ } catch (error) {
1061
+ const message = error instanceof Error ? error.message : "Unknown error";
1062
+ return {
1063
+ content: [
1064
+ {
1065
+ type: "text",
1066
+ text: `Error setting up project: ${message}`
1067
+ }
1068
+ ],
1069
+ isError: true
1070
+ };
1071
+ }
1072
+ }
1073
+ );
1074
+ server.registerTool(
1075
+ "forprompt_generate_config",
1076
+ {
1077
+ description: "Generate a .forprompt configuration file for a project. Returns the config content that should be written to .forprompt file in the project root.",
1078
+ inputSchema: GenerateConfigInputSchema
1079
+ },
1080
+ async ({ projectPath, apiKey, baseUrl }) => {
1081
+ try {
1082
+ const configLines = [
1083
+ `# ForPrompt Configuration`,
1084
+ `# Generated by ForPrompt MCP Server`,
1085
+ ``
1086
+ ];
1087
+ if (apiKey) {
1088
+ configLines.push(`FORPROMPT_API_KEY=${apiKey}`);
1089
+ } else {
1090
+ configLines.push(`# Add your API key here:`);
1091
+ configLines.push(`FORPROMPT_API_KEY=your_api_key_here`);
1092
+ }
1093
+ if (baseUrl) {
1094
+ configLines.push(`FORPROMPT_BASE_URL=${baseUrl}`);
1095
+ }
1096
+ const configContent = configLines.join("\n");
1097
+ const configPath = `${projectPath}/.forprompt`;
1098
+ const lines = [
1099
+ `# ForPrompt Configuration`,
1100
+ ``,
1101
+ `Create a file at \`${configPath}\` with the following content:`,
1102
+ ``,
1103
+ "```env",
1104
+ configContent,
1105
+ "```",
1106
+ ``,
1107
+ `## Alternative: Environment Variables`,
1108
+ ``,
1109
+ `Instead of a config file, you can set environment variables:`,
1110
+ ``,
1111
+ "```bash",
1112
+ `export FORPROMPT_API_KEY=your_api_key_here`,
1113
+ "```",
1114
+ ``,
1115
+ `## Get Your API Key`,
1116
+ ``,
1117
+ `1. Go to https://forprompt.dev/dashboard`,
1118
+ `2. Navigate to your organization settings`,
1119
+ `3. Create or copy your API key`,
1120
+ ``,
1121
+ `**Important:** Add \`.forprompt\` to your \`.gitignore\` to keep your API key secure!`
1122
+ ];
1123
+ return {
1124
+ content: [
1125
+ {
1126
+ type: "text",
1127
+ text: lines.join("\n")
1128
+ }
1129
+ ]
1130
+ };
1131
+ } catch (error) {
1132
+ const message = error instanceof Error ? error.message : "Unknown error";
1133
+ return {
1134
+ content: [
1135
+ {
1136
+ type: "text",
1137
+ text: `Error generating config: ${message}`
1138
+ }
1139
+ ],
1140
+ isError: true
1141
+ };
1142
+ }
1143
+ }
1144
+ );
1145
+ server.registerTool(
1146
+ "forprompt_generate_example",
1147
+ {
1148
+ description: "Generate example code showing how to use ForPrompt SDK. Supports different languages and use cases like basic usage, streaming, React hooks, and Next.js API routes.",
1149
+ inputSchema: GenerateExampleInputSchema
1150
+ },
1151
+ async ({ language, useCase, promptKey }) => {
1152
+ try {
1153
+ const key = promptKey || "my_prompt";
1154
+ let code;
1155
+ let description;
1156
+ if (language === "python") {
1157
+ switch (useCase) {
1158
+ case "streaming":
1159
+ description = "Python streaming example with ForPrompt";
1160
+ code = `from forprompt import ForPrompt
1161
+ import os
1162
+
1163
+ # Initialize the client
1164
+ client = ForPrompt(api_key=os.environ.get("FORPROMPT_API_KEY"))
1165
+
1166
+ # Get the prompt
1167
+ prompt = client.get_prompt("${key}")
1168
+
1169
+ # Use with your LLM (example with OpenAI)
1170
+ from openai import OpenAI
1171
+
1172
+ openai = OpenAI()
1173
+
1174
+ # Stream the response
1175
+ stream = openai.chat.completions.create(
1176
+ model="gpt-4",
1177
+ messages=[
1178
+ {"role": "system", "content": prompt.system_prompt},
1179
+ {"role": "user", "content": "Your user message here"}
1180
+ ],
1181
+ stream=True
1182
+ )
1183
+
1184
+ for chunk in stream:
1185
+ if chunk.choices[0].delta.content:
1186
+ print(chunk.choices[0].delta.content, end="")`;
1187
+ break;
1188
+ case "with-tools":
1189
+ description = "Python example with tools/functions";
1190
+ code = `from forprompt import ForPrompt
1191
+ import os
1192
+ import json
1193
+
1194
+ client = ForPrompt(api_key=os.environ.get("FORPROMPT_API_KEY"))
1195
+
1196
+ # Get the prompt with tools
1197
+ prompt = client.get_prompt("${key}")
1198
+
1199
+ # Define your tools
1200
+ tools = [
1201
+ {
1202
+ "type": "function",
1203
+ "function": {
1204
+ "name": "get_weather",
1205
+ "description": "Get current weather for a location",
1206
+ "parameters": {
1207
+ "type": "object",
1208
+ "properties": {
1209
+ "location": {"type": "string", "description": "City name"}
1210
+ },
1211
+ "required": ["location"]
1212
+ }
1213
+ }
1214
+ }
1215
+ ]
1216
+
1217
+ # Use with OpenAI
1218
+ from openai import OpenAI
1219
+
1220
+ openai = OpenAI()
1221
+
1222
+ response = openai.chat.completions.create(
1223
+ model="gpt-4",
1224
+ messages=[
1225
+ {"role": "system", "content": prompt.system_prompt},
1226
+ {"role": "user", "content": "What's the weather in Tokyo?"}
1227
+ ],
1228
+ tools=tools,
1229
+ tool_choice="auto"
1230
+ )
1231
+
1232
+ print(response.choices[0].message)`;
1233
+ break;
1234
+ default:
1235
+ description = "Basic Python usage example";
1236
+ code = `from forprompt import ForPrompt
1237
+ import os
1238
+
1239
+ # Initialize the client
1240
+ client = ForPrompt(api_key=os.environ.get("FORPROMPT_API_KEY"))
1241
+
1242
+ # Get a prompt by key
1243
+ prompt = client.get_prompt("${key}")
1244
+
1245
+ print(f"Prompt: {prompt.name}")
1246
+ print(f"Version: {prompt.version_number}")
1247
+ print(f"System Prompt: {prompt.system_prompt}")
1248
+
1249
+ # Use the prompt with your LLM
1250
+ from openai import OpenAI
1251
+
1252
+ openai = OpenAI()
1253
+
1254
+ response = openai.chat.completions.create(
1255
+ model="gpt-4",
1256
+ messages=[
1257
+ {"role": "system", "content": prompt.system_prompt},
1258
+ {"role": "user", "content": "Your user message here"}
1259
+ ]
1260
+ )
1261
+
1262
+ print(response.choices[0].message.content)`;
1263
+ }
1264
+ } else {
1265
+ const isTS = language === "typescript";
1266
+ const ext = isTS ? "ts" : "js";
1267
+ switch (useCase) {
1268
+ case "streaming":
1269
+ description = "Streaming example with ForPrompt";
1270
+ code = `import { forprompt } from '@forprompt/sdk';
1271
+ import OpenAI from 'openai';
1272
+
1273
+ async function main() {
1274
+ // Get the prompt
1275
+ const prompt = await forprompt.getPrompt('${key}');
1276
+
1277
+ const openai = new OpenAI();
1278
+
1279
+ // Stream the response
1280
+ const stream = await openai.chat.completions.create({
1281
+ model: 'gpt-4',
1282
+ messages: [
1283
+ { role: 'system', content: prompt.systemPrompt },
1284
+ { role: 'user', content: 'Your user message here' }
1285
+ ],
1286
+ stream: true,
1287
+ });
1288
+
1289
+ for await (const chunk of stream) {
1290
+ const content = chunk.choices[0]?.delta?.content;
1291
+ if (content) process.stdout.write(content);
1292
+ }
1293
+ }
1294
+
1295
+ main();`;
1296
+ break;
1297
+ case "react-hook":
1298
+ description = "React hook example";
1299
+ code = `import { useState, useEffect } from 'react';
1300
+ import { forprompt } from '@forprompt/sdk';
1301
+ ${isTS ? "import type { Prompt } from '@forprompt/sdk';\n" : ""}
1302
+ // Custom hook to fetch a ForPrompt prompt
1303
+ export function usePrompt(key${isTS ? ": string" : ""}) {
1304
+ const [prompt, setPrompt] = useState${isTS ? "<Prompt | null>" : ""}(null);
1305
+ const [loading, setLoading] = useState(true);
1306
+ const [error, setError] = useState${isTS ? "<Error | null>" : ""}(null);
1307
+
1308
+ useEffect(() => {
1309
+ let cancelled = false;
1310
+
1311
+ async function fetchPrompt() {
1312
+ try {
1313
+ setLoading(true);
1314
+ const data = await forprompt.getPrompt(key);
1315
+ if (!cancelled) {
1316
+ setPrompt(data);
1317
+ setError(null);
1318
+ }
1319
+ } catch (err) {
1320
+ if (!cancelled) {
1321
+ setError(err${isTS ? " as Error" : ""});
1322
+ }
1323
+ } finally {
1324
+ if (!cancelled) {
1325
+ setLoading(false);
1326
+ }
1327
+ }
1328
+ }
1329
+
1330
+ fetchPrompt();
1331
+
1332
+ return () => { cancelled = true; };
1333
+ }, [key]);
1334
+
1335
+ return { prompt, loading, error };
1336
+ }
1337
+
1338
+ // Usage in a component
1339
+ function ChatComponent() {
1340
+ const { prompt, loading, error } = usePrompt('${key}');
1341
+
1342
+ if (loading) return <div>Loading prompt...</div>;
1343
+ if (error) return <div>Error: {error.message}</div>;
1344
+
1345
+ return (
1346
+ <div>
1347
+ <h1>{prompt${isTS ? "!" : ""}.name}</h1>
1348
+ <p>Version: {prompt${isTS ? "!" : ""}.versionNumber}</p>
1349
+ {/* Use prompt.systemPrompt with your AI chat */}
1350
+ </div>
1351
+ );
1352
+ }`;
1353
+ break;
1354
+ case "nextjs-api":
1355
+ description = "Next.js API route example";
1356
+ code = `// app/api/chat/route.${ext}
1357
+ import { forprompt } from '@forprompt/sdk';
1358
+ import OpenAI from 'openai';
1359
+ import { NextResponse } from 'next/server';
1360
+ ${isTS ? "\nexport const runtime = 'edge';\n" : ""}
1361
+ const openai = new OpenAI();
1362
+
1363
+ export async function POST(request${isTS ? ": Request" : ""}) {
1364
+ try {
1365
+ const { message, promptKey } = await request.json();
1366
+
1367
+ // Fetch the prompt from ForPrompt
1368
+ const prompt = await forprompt.getPrompt(promptKey || '${key}');
1369
+
1370
+ // Create completion with the system prompt
1371
+ const response = await openai.chat.completions.create({
1372
+ model: 'gpt-4',
1373
+ messages: [
1374
+ { role: 'system', content: prompt.systemPrompt },
1375
+ { role: 'user', content: message }
1376
+ ],
1377
+ });
1378
+
1379
+ return NextResponse.json({
1380
+ content: response.choices[0].message.content,
1381
+ promptVersion: prompt.versionNumber,
1382
+ });
1383
+ } catch (error) {
1384
+ console.error('Chat API error:', error);
1385
+ return NextResponse.json(
1386
+ { error: 'Failed to process chat request' },
1387
+ { status: 500 }
1388
+ );
1389
+ }
1390
+ }`;
1391
+ break;
1392
+ case "with-tools":
1393
+ description = "Example with tools/functions";
1394
+ code = `import { forprompt } from '@forprompt/sdk';
1395
+ import OpenAI from 'openai';
1396
+
1397
+ const openai = new OpenAI();
1398
+
1399
+ // Define your tools
1400
+ const tools${isTS ? ": OpenAI.ChatCompletionTool[]" : ""} = [
1401
+ {
1402
+ type: 'function',
1403
+ function: {
1404
+ name: 'get_weather',
1405
+ description: 'Get current weather for a location',
1406
+ parameters: {
1407
+ type: 'object',
1408
+ properties: {
1409
+ location: { type: 'string', description: 'City name' }
1410
+ },
1411
+ required: ['location']
1412
+ }
1413
+ }
1414
+ }
1415
+ ];
1416
+
1417
+ async function main() {
1418
+ const prompt = await forprompt.getPrompt('${key}');
1419
+
1420
+ const response = await openai.chat.completions.create({
1421
+ model: 'gpt-4',
1422
+ messages: [
1423
+ { role: 'system', content: prompt.systemPrompt },
1424
+ { role: 'user', content: "What's the weather in Tokyo?" }
1425
+ ],
1426
+ tools,
1427
+ tool_choice: 'auto',
1428
+ });
1429
+
1430
+ console.log(response.choices[0].message);
1431
+ }
1432
+
1433
+ main();`;
1434
+ break;
1435
+ default:
1436
+ description = "Basic usage example";
1437
+ code = `import { forprompt } from '@forprompt/sdk';
1438
+ import OpenAI from 'openai';
1439
+
1440
+ async function main() {
1441
+ // Get a prompt by key
1442
+ const prompt = await forprompt.getPrompt('${key}');
1443
+
1444
+ console.log('Prompt:', prompt.name);
1445
+ console.log('Version:', prompt.versionNumber);
1446
+ console.log('System Prompt:', prompt.systemPrompt);
1447
+
1448
+ // Use with OpenAI
1449
+ const openai = new OpenAI();
1450
+
1451
+ const response = await openai.chat.completions.create({
1452
+ model: 'gpt-4',
1453
+ messages: [
1454
+ { role: 'system', content: prompt.systemPrompt },
1455
+ { role: 'user', content: 'Your user message here' }
1456
+ ],
1457
+ });
1458
+
1459
+ console.log(response.choices[0].message.content);
1460
+ }
1461
+
1462
+ main();`;
1463
+ }
1464
+ }
1465
+ const lines = [
1466
+ `# ${description}`,
1467
+ ``,
1468
+ `**Language:** ${language}`,
1469
+ `**Use Case:** ${useCase}`,
1470
+ ``,
1471
+ "```" + (language === "python" ? "python" : language),
1472
+ code,
1473
+ "```",
1474
+ ``,
1475
+ `## Setup Required`,
1476
+ ``,
1477
+ `1. Install the ForPrompt SDK`,
1478
+ `2. Set your \`FORPROMPT_API_KEY\` environment variable`,
1479
+ `3. Create a prompt with key \`${key}\` in ForPrompt dashboard`
1480
+ ];
1481
+ return {
1482
+ content: [
1483
+ {
1484
+ type: "text",
1485
+ text: lines.join("\n")
1486
+ }
1487
+ ]
1488
+ };
1489
+ } catch (error) {
1490
+ const message = error instanceof Error ? error.message : "Unknown error";
1491
+ return {
1492
+ content: [
1493
+ {
1494
+ type: "text",
1495
+ text: `Error generating example: ${message}`
1496
+ }
1497
+ ],
1498
+ isError: true
1499
+ };
1500
+ }
1501
+ }
1502
+ );
1503
+ server.registerTool(
1504
+ "forprompt_integration_guide",
1505
+ {
1506
+ description: "Get a step-by-step integration guide for ForPrompt with specific frameworks like Next.js, React, Express, FastAPI, Django, or Flask.",
1507
+ inputSchema: GetIntegrationGuideInputSchema
1508
+ },
1509
+ async ({ framework, language }) => {
1510
+ try {
1511
+ let guide;
1512
+ switch (framework) {
1513
+ case "nextjs":
1514
+ guide = `# ForPrompt + Next.js Integration Guide
1515
+
1516
+ ## 1. Install the SDK
1517
+
1518
+ \`\`\`bash
1519
+ npm install @forprompt/sdk
1520
+ # or: pnpm add @forprompt/sdk
1521
+ \`\`\`
1522
+
1523
+ ## 2. Set up environment variables
1524
+
1525
+ Add to your \`.env.local\`:
1526
+
1527
+ \`\`\`env
1528
+ FORPROMPT_API_KEY=your_api_key_here
1529
+ \`\`\`
1530
+
1531
+ ## 3. Create an API route
1532
+
1533
+ \`\`\`typescript
1534
+ // app/api/chat/route.ts
1535
+ import { forprompt } from '@forprompt/sdk';
1536
+ import { NextResponse } from 'next/server';
1537
+
1538
+ export async function POST(request: Request) {
1539
+ const { message, promptKey } = await request.json();
1540
+
1541
+ // Fetch prompt from ForPrompt
1542
+ const prompt = await forprompt.getPrompt(promptKey);
1543
+
1544
+ // Use prompt.systemPrompt with your LLM
1545
+ // ... your AI logic here
1546
+
1547
+ return NextResponse.json({ response: '...' });
1548
+ }
1549
+ \`\`\`
1550
+
1551
+ ## 4. Create a client hook (optional)
1552
+
1553
+ \`\`\`typescript
1554
+ // hooks/useForPrompt.ts
1555
+ 'use client';
1556
+ import { forprompt } from '@forprompt/sdk';
1557
+ import { useEffect, useState } from 'react';
1558
+
1559
+ export function usePrompt(key: string) {
1560
+ const [prompt, setPrompt] = useState(null);
1561
+
1562
+ useEffect(() => {
1563
+ forprompt.getPrompt(key).then(setPrompt);
1564
+ }, [key]);
1565
+
1566
+ return prompt;
1567
+ }
1568
+ \`\`\`
1569
+
1570
+ ## 5. Best Practices
1571
+
1572
+ - Cache prompts in production using Next.js caching
1573
+ - Use server components for initial prompt fetch
1574
+ - Consider using SWR or React Query for client-side caching`;
1575
+ break;
1576
+ case "react":
1577
+ guide = `# ForPrompt + React Integration Guide
1578
+
1579
+ ## 1. Install the SDK
1580
+
1581
+ \`\`\`bash
1582
+ npm install @forprompt/sdk
1583
+ \`\`\`
1584
+
1585
+ ## 2. Create a custom hook
1586
+
1587
+ \`\`\`typescript
1588
+ // hooks/usePrompt.ts
1589
+ import { useState, useEffect } from 'react';
1590
+ import { forprompt, Prompt } from '@forprompt/sdk';
1591
+
1592
+ export function usePrompt(key: string) {
1593
+ const [prompt, setPrompt] = useState<Prompt | null>(null);
1594
+ const [loading, setLoading] = useState(true);
1595
+ const [error, setError] = useState<Error | null>(null);
1596
+
1597
+ useEffect(() => {
1598
+ forprompt.getPrompt(key)
1599
+ .then(setPrompt)
1600
+ .catch(setError)
1601
+ .finally(() => setLoading(false));
1602
+ }, [key]);
1603
+
1604
+ return { prompt, loading, error };
1605
+ }
1606
+ \`\`\`
1607
+
1608
+ ## 3. Use in components
1609
+
1610
+ \`\`\`tsx
1611
+ function ChatBot() {
1612
+ const { prompt, loading } = usePrompt('customer_support');
1613
+
1614
+ if (loading) return <Spinner />;
1615
+
1616
+ return <Chat systemPrompt={prompt.systemPrompt} />;
1617
+ }
1618
+ \`\`\``;
1619
+ break;
1620
+ case "express":
1621
+ guide = `# ForPrompt + Express Integration Guide
1622
+
1623
+ ## 1. Install the SDK
1624
+
1625
+ \`\`\`bash
1626
+ npm install @forprompt/sdk
1627
+ \`\`\`
1628
+
1629
+ ## 2. Create a middleware (optional)
1630
+
1631
+ \`\`\`typescript
1632
+ // middleware/forprompt.ts
1633
+ import { forprompt } from '@forprompt/sdk';
1634
+
1635
+ export async function loadPrompt(req, res, next) {
1636
+ try {
1637
+ const promptKey = req.query.promptKey || req.body.promptKey;
1638
+ if (promptKey) {
1639
+ req.prompt = await forprompt.getPrompt(promptKey);
1640
+ }
1641
+ next();
1642
+ } catch (error) {
1643
+ next(error);
1644
+ }
1645
+ }
1646
+ \`\`\`
1647
+
1648
+ ## 3. Use in routes
1649
+
1650
+ \`\`\`typescript
1651
+ import express from 'express';
1652
+ import { forprompt } from '@forprompt/sdk';
1653
+
1654
+ const app = express();
1655
+
1656
+ app.post('/api/chat', async (req, res) => {
1657
+ const { message, promptKey } = req.body;
1658
+
1659
+ const prompt = await forprompt.getPrompt(promptKey);
1660
+
1661
+ // Use prompt.systemPrompt with your LLM
1662
+ // ...
1663
+
1664
+ res.json({ response: '...' });
1665
+ });
1666
+ \`\`\``;
1667
+ break;
1668
+ case "fastapi":
1669
+ guide = `# ForPrompt + FastAPI Integration Guide
1670
+
1671
+ ## 1. Install the SDK
1672
+
1673
+ \`\`\`bash
1674
+ pip install forprompt
1675
+ \`\`\`
1676
+
1677
+ ## 2. Create a dependency
1678
+
1679
+ \`\`\`python
1680
+ # dependencies.py
1681
+ from forprompt import ForPrompt
1682
+ import os
1683
+
1684
+ def get_forprompt():
1685
+ return ForPrompt(api_key=os.environ.get("FORPROMPT_API_KEY"))
1686
+ \`\`\`
1687
+
1688
+ ## 3. Use in routes
1689
+
1690
+ \`\`\`python
1691
+ from fastapi import FastAPI, Depends
1692
+ from forprompt import ForPrompt
1693
+ from dependencies import get_forprompt
1694
+
1695
+ app = FastAPI()
1696
+
1697
+ @app.post("/api/chat")
1698
+ async def chat(
1699
+ message: str,
1700
+ prompt_key: str,
1701
+ fp: ForPrompt = Depends(get_forprompt)
1702
+ ):
1703
+ prompt = fp.get_prompt(prompt_key)
1704
+
1705
+ # Use prompt.system_prompt with your LLM
1706
+ # ...
1707
+
1708
+ return {"response": "..."}
1709
+ \`\`\`
1710
+
1711
+ ## 4. Best Practices
1712
+
1713
+ - Cache prompts using functools.lru_cache or Redis
1714
+ - Use async version for better performance
1715
+ - Consider using Pydantic models for prompt data`;
1716
+ break;
1717
+ case "django":
1718
+ guide = `# ForPrompt + Django Integration Guide
1719
+
1720
+ ## 1. Install the SDK
1721
+
1722
+ \`\`\`bash
1723
+ pip install forprompt
1724
+ \`\`\`
1725
+
1726
+ ## 2. Add to settings
1727
+
1728
+ \`\`\`python
1729
+ # settings.py
1730
+ FORPROMPT_API_KEY = os.environ.get("FORPROMPT_API_KEY")
1731
+ \`\`\`
1732
+
1733
+ ## 3. Create a utility
1734
+
1735
+ \`\`\`python
1736
+ # utils/forprompt.py
1737
+ from forprompt import ForPrompt
1738
+ from django.conf import settings
1739
+ from functools import lru_cache
1740
+
1741
+ @lru_cache(maxsize=100)
1742
+ def get_prompt(key: str):
1743
+ client = ForPrompt(api_key=settings.FORPROMPT_API_KEY)
1744
+ return client.get_prompt(key)
1745
+ \`\`\`
1746
+
1747
+ ## 4. Use in views
1748
+
1749
+ \`\`\`python
1750
+ from django.http import JsonResponse
1751
+ from utils.forprompt import get_prompt
1752
+
1753
+ def chat_view(request):
1754
+ prompt_key = request.POST.get('prompt_key')
1755
+ prompt = get_prompt(prompt_key)
1756
+
1757
+ # Use prompt.system_prompt with your LLM
1758
+
1759
+ return JsonResponse({"response": "..."})
1760
+ \`\`\``;
1761
+ break;
1762
+ case "flask":
1763
+ guide = `# ForPrompt + Flask Integration Guide
1764
+
1765
+ ## 1. Install the SDK
1766
+
1767
+ \`\`\`bash
1768
+ pip install forprompt
1769
+ \`\`\`
1770
+
1771
+ ## 2. Initialize the client
1772
+
1773
+ \`\`\`python
1774
+ # app.py
1775
+ from flask import Flask, request, jsonify
1776
+ from forprompt import ForPrompt
1777
+ import os
1778
+
1779
+ app = Flask(__name__)
1780
+ forprompt_client = ForPrompt(api_key=os.environ.get("FORPROMPT_API_KEY"))
1781
+
1782
+ @app.route('/api/chat', methods=['POST'])
1783
+ def chat():
1784
+ data = request.json
1785
+ prompt = forprompt_client.get_prompt(data['prompt_key'])
1786
+
1787
+ # Use prompt.system_prompt with your LLM
1788
+
1789
+ return jsonify({"response": "..."})
1790
+ \`\`\``;
1791
+ break;
1792
+ default:
1793
+ guide = `# ForPrompt Generic Integration Guide
1794
+
1795
+ ## TypeScript/JavaScript
1796
+
1797
+ \`\`\`typescript
1798
+ import { forprompt } from '@forprompt/sdk';
1799
+
1800
+ const prompt = await forprompt.getPrompt('your_prompt_key');
1801
+ console.log(prompt.systemPrompt);
1802
+ \`\`\`
1803
+
1804
+ ## Python
1805
+
1806
+ \`\`\`python
1807
+ from forprompt import ForPrompt
1808
+ import os
1809
+
1810
+ client = ForPrompt(api_key=os.environ.get("FORPROMPT_API_KEY"))
1811
+ prompt = client.get_prompt("your_prompt_key")
1812
+ print(prompt.system_prompt)
1813
+ \`\`\`
1814
+
1815
+ ## Environment Setup
1816
+
1817
+ 1. Get your API key from https://forprompt.dev/dashboard
1818
+ 2. Set \`FORPROMPT_API_KEY\` environment variable
1819
+ 3. Install the SDK for your language
1820
+ 4. Start fetching prompts!`;
1821
+ }
1822
+ return {
1823
+ content: [
1824
+ {
1825
+ type: "text",
1826
+ text: guide
1827
+ }
1828
+ ]
1829
+ };
1830
+ } catch (error) {
1831
+ const message = error instanceof Error ? error.message : "Unknown error";
1832
+ return {
1833
+ content: [
1834
+ {
1835
+ type: "text",
1836
+ text: `Error generating guide: ${message}`
1837
+ }
1838
+ ],
1839
+ isError: true
1840
+ };
1841
+ }
1842
+ }
1843
+ );
1844
+ }
1845
+
1846
+ // src/mcp/resources.ts
1847
+ var DEFAULT_BASE_URL3 = "https://wooden-fox-811.convex.site";
1848
+ async function fetchAllPrompts2(config) {
1849
+ const apiKey = config.apiKey || process.env.FORPROMPT_API_KEY;
1850
+ const baseUrl = (config.baseUrl || process.env.FORPROMPT_BASE_URL || DEFAULT_BASE_URL3).replace(/\/$/, "");
1851
+ if (!apiKey) {
1852
+ throw new Error(
1853
+ "API key is required. Set FORPROMPT_API_KEY environment variable."
1854
+ );
1855
+ }
1856
+ const response = await fetch(`${baseUrl}/api/sync`, {
1857
+ method: "GET",
1858
+ headers: {
1859
+ "Content-Type": "application/json",
1860
+ "X-API-Key": apiKey
1861
+ }
1862
+ });
1863
+ if (!response.ok) {
1864
+ const errorData = await response.json().catch(() => ({
1865
+ error: "Unknown error"
1866
+ }));
1867
+ throw new Error(errorData.error || `Failed to fetch prompts`);
1868
+ }
1869
+ const data = await response.json();
1870
+ return data.prompts;
1871
+ }
1872
+ function parseUri(uri) {
1873
+ const match = uri.match(/^forprompt:\/\/prompts(?:\/([^/]+))?(?:\/(v\d+|metadata))?$/);
1874
+ if (!match) {
1875
+ return { type: "list" };
1876
+ }
1877
+ const [, key, suffix] = match;
1878
+ if (!key) {
1879
+ return { type: "list" };
1880
+ }
1881
+ if (suffix === "metadata") {
1882
+ return { key, type: "metadata" };
1883
+ }
1884
+ if (suffix?.startsWith("v")) {
1885
+ const version = parseInt(suffix.slice(1), 10);
1886
+ return { key, version, type: "prompt" };
1887
+ }
1888
+ return { key, type: "prompt" };
1889
+ }
1890
+ function formatPromptResource(prompt) {
1891
+ const sections = [];
1892
+ sections.push(`# ${prompt.name}`);
1893
+ sections.push("");
1894
+ sections.push(`Key: ${prompt.key}`);
1895
+ sections.push(`Version: ${prompt.versionNumber}`);
1896
+ sections.push(`Updated: ${new Date(prompt.updatedAt).toISOString()}`);
1897
+ if (prompt.description) {
1898
+ sections.push("");
1899
+ sections.push(`## Description`);
1900
+ sections.push(prompt.description);
1901
+ }
1902
+ sections.push("");
1903
+ sections.push("## System Prompt");
1904
+ sections.push("");
1905
+ sections.push(prompt.systemPrompt);
1906
+ if (prompt.purpose) {
1907
+ sections.push("");
1908
+ sections.push("## Purpose");
1909
+ sections.push(prompt.purpose);
1910
+ }
1911
+ if (prompt.expectedBehavior) {
1912
+ sections.push("");
1913
+ sections.push("## Expected Behavior");
1914
+ sections.push(prompt.expectedBehavior);
1915
+ }
1916
+ if (prompt.inputFormat) {
1917
+ sections.push("");
1918
+ sections.push("## Input Format");
1919
+ sections.push(prompt.inputFormat);
1920
+ }
1921
+ if (prompt.outputFormat) {
1922
+ sections.push("");
1923
+ sections.push("## Output Format");
1924
+ sections.push(prompt.outputFormat);
1925
+ }
1926
+ if (prompt.constraints) {
1927
+ sections.push("");
1928
+ sections.push("## Constraints");
1929
+ sections.push(prompt.constraints);
1930
+ }
1931
+ if (prompt.useCases) {
1932
+ sections.push("");
1933
+ sections.push("## Use Cases");
1934
+ sections.push(prompt.useCases);
1935
+ }
1936
+ return sections.join("\n");
1937
+ }
1938
+ function registerResources(server, client, config) {
1939
+ server.resource(
1940
+ "forprompt://prompts/{key}",
1941
+ "Access a ForPrompt prompt by its key. Returns the system prompt and all metadata.",
1942
+ async (uri) => {
1943
+ const parsed = parseUri(uri.href);
1944
+ if (parsed.type === "list" || !parsed.key) {
1945
+ const prompts = await fetchAllPrompts2(config);
1946
+ const list = prompts.map((p) => `- ${p.key}: ${p.name} (v${p.versionNumber})`).join("\n");
1947
+ return {
1948
+ contents: [
1949
+ {
1950
+ uri: uri.href,
1951
+ mimeType: "text/plain",
1952
+ text: `# ForPrompt Prompts
1953
+
1954
+ ${prompts.length} prompt(s) available:
1955
+
1956
+ ${list}`
1957
+ }
1958
+ ]
1959
+ };
1960
+ }
1961
+ if (parsed.type === "metadata") {
1962
+ const prompt2 = await client.getPrompt(parsed.key);
1963
+ const metadata = {
1964
+ key: prompt2.key,
1965
+ name: prompt2.name,
1966
+ description: prompt2.description,
1967
+ versionNumber: prompt2.versionNumber,
1968
+ updatedAt: prompt2.updatedAt,
1969
+ purpose: prompt2.purpose,
1970
+ expectedBehavior: prompt2.expectedBehavior,
1971
+ inputFormat: prompt2.inputFormat,
1972
+ outputFormat: prompt2.outputFormat,
1973
+ constraints: prompt2.constraints,
1974
+ useCases: prompt2.useCases
1975
+ };
1976
+ return {
1977
+ contents: [
1978
+ {
1979
+ uri: uri.href,
1980
+ mimeType: "application/json",
1981
+ text: JSON.stringify(metadata, null, 2)
1982
+ }
1983
+ ]
1984
+ };
1985
+ }
1986
+ const prompt = await client.getPrompt(parsed.key, {
1987
+ version: parsed.version
1988
+ });
1989
+ return {
1990
+ contents: [
1991
+ {
1992
+ uri: uri.href,
1993
+ mimeType: "text/plain",
1994
+ text: formatPromptResource(prompt)
1995
+ }
1996
+ ]
1997
+ };
1998
+ }
1999
+ );
2000
+ }
2001
+
2002
+ // package.json
2003
+ var package_default = {
2004
+ name: "@forprompt/sdk",
2005
+ version: "0.1.0",
2006
+ description: "ForPrompt SDK - Sync and manage AI prompts from your ForPrompt projects",
2007
+ type: "module",
2008
+ main: "./dist/index.cjs",
2009
+ module: "./dist/index.js",
2010
+ types: "./dist/index.d.ts",
2011
+ bin: {
2012
+ forprompt: "./dist/cli/index.js",
2013
+ "forprompt-mcp": "./dist/mcp/server.js"
2014
+ },
2015
+ exports: {
2016
+ ".": {
2017
+ types: "./dist/index.d.ts",
2018
+ import: "./dist/index.js",
2019
+ require: "./dist/index.cjs"
2020
+ },
2021
+ "./mcp": {
2022
+ types: "./dist/mcp/index.d.ts",
2023
+ import: "./dist/mcp/index.js"
2024
+ }
2025
+ },
2026
+ files: [
2027
+ "dist",
2028
+ "README.md"
2029
+ ],
2030
+ license: "AGPL-3.0-or-later",
2031
+ author: "ForPrompt",
2032
+ repository: {
2033
+ type: "git",
2034
+ url: "https://github.com/ardacanuckan/forprompt.git",
2035
+ directory: "packages/sdk"
2036
+ },
2037
+ homepage: "https://forprompt.dev",
2038
+ bugs: {
2039
+ url: "https://github.com/forprompt/sdk/issues"
2040
+ },
2041
+ keywords: [
2042
+ "forprompt",
2043
+ "prompts",
2044
+ "ai",
2045
+ "llm",
2046
+ "prompt-management",
2047
+ "cli",
2048
+ "sdk",
2049
+ "openai",
2050
+ "anthropic",
2051
+ "chatgpt"
2052
+ ],
2053
+ engines: {
2054
+ node: ">=18.0.0"
2055
+ },
2056
+ publishConfig: {
2057
+ access: "public"
2058
+ },
2059
+ scripts: {
2060
+ build: "tsup",
2061
+ prepublishOnly: "pnpm run typecheck && pnpm run build",
2062
+ prepack: "pnpm run build",
2063
+ clean: "rm -rf dist node_modules coverage",
2064
+ dev: "tsup --watch",
2065
+ typecheck: "tsc --noEmit",
2066
+ lint: "eslint src/",
2067
+ test: "echo 'Tests temporarily disabled due to Vitest/ESM configuration issue. Tests are written and ready in src/__tests__/' && exit 0",
2068
+ "test:watch": "vitest",
2069
+ "test:coverage": "vitest run --coverage"
2070
+ },
2071
+ dependencies: {
2072
+ "@modelcontextprotocol/sdk": "^1.0.0",
2073
+ zod: "^3.24.0"
2074
+ },
2075
+ devDependencies: {
2076
+ "@forprompt/eslint-config": "workspace:*",
2077
+ "@forprompt/tsconfig": "workspace:*",
2078
+ "@types/node": "^20.0.0",
2079
+ "@vitest/coverage-v8": "^2.1.0",
2080
+ eslint: "^9.0.0",
2081
+ tsup: "^8.0.0",
2082
+ typescript: "^5.3.0",
2083
+ vitest: "^2.1.0"
2084
+ }
2085
+ };
2086
+
2087
+ // src/version.ts
2088
+ var VERSION = package_default.version;
2089
+
2090
+ // src/mcp/server.ts
2091
+ var ForPromptMcpServer = class {
2092
+ mcpServer;
2093
+ forprompt;
2094
+ config;
2095
+ constructor(config = {}) {
2096
+ this.config = config;
2097
+ this.forprompt = createForPrompt({
2098
+ apiKey: config.apiKey,
2099
+ baseUrl: config.baseUrl
2100
+ });
2101
+ this.mcpServer = new McpServer({
2102
+ name: "forprompt",
2103
+ version: VERSION
2104
+ });
2105
+ this.registerCapabilities();
2106
+ }
2107
+ registerCapabilities() {
2108
+ registerTools(this.mcpServer, this.forprompt, this.config);
2109
+ registerResources(this.mcpServer, this.forprompt, this.config);
2110
+ }
2111
+ /**
2112
+ * Start the MCP server with stdio transport
2113
+ */
2114
+ async start() {
2115
+ const transport = new StdioServerTransport();
2116
+ await this.mcpServer.connect(transport);
2117
+ }
2118
+ /**
2119
+ * Get the underlying MCP server instance
2120
+ */
2121
+ getServer() {
2122
+ return this.mcpServer;
2123
+ }
2124
+ };
2125
+ async function startMcpServer(config = {}) {
2126
+ const server = new ForPromptMcpServer(config);
2127
+ await server.start();
2128
+ return server;
2129
+ }
2130
+ function isMainModule() {
2131
+ const arg1 = process.argv[1] || "";
2132
+ return arg1.endsWith("forprompt-mcp") || arg1.endsWith("server.js") || arg1.includes("mcp/server");
2133
+ }
2134
+ if (isMainModule()) {
2135
+ startMcpServer().catch((error) => {
2136
+ console.error("Failed to start MCP server:", error);
2137
+ process.exit(1);
2138
+ });
2139
+ }
2140
+
2141
+ export {
2142
+ ForPromptMcpServer,
2143
+ startMcpServer
2144
+ };
2145
+ //# sourceMappingURL=chunk-2ABKAGKB.js.map