@iflow-mcp/instructa-ai-prompts-mcp 0.0.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/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Instructa AI - MCP Prompts API
2
+
3
+ This repository contains a Model Context Protocol (MCP) implementation for managing and serving AI prompts. The project is built using TypeScript and follows a monorepo structure using pnpm workspaces.
4
+
5
+ ## 🚀 Features
6
+
7
+ - MCP (Model Context Protocol) implementation
8
+ - TypeScript-based architecture
9
+ - Monorepo structure using pnpm workspaces
10
+ - Environment-based configuration
11
+
12
+ ## 📋 Prerequisites
13
+
14
+ - Node.js (LTS version recommended)
15
+ - pnpm (Package manager)
16
+
17
+ ## 🛠️ Installation
18
+
19
+ 1. Clone the repository:
20
+ ```bash
21
+ git clone https://github.com/yourusername/instructa-ai.git
22
+ cd instructa-ai
23
+ ```
24
+
25
+ 2. Install dependencies:
26
+ ```bash
27
+ pnpm install
28
+ ```
29
+
30
+ 3. Set up environment variables:
31
+ ```bash
32
+ cp packages/mcp/.env.dist packages/mcp/.env
33
+ # Edit .env file with your configuration
34
+ ```
35
+
36
+ ## 🏃‍♂️ Development
37
+
38
+ To start the development server:
39
+
40
+ ```bash
41
+ # Start MCP development server
42
+ pnpm dev:mcp
43
+
44
+ # Build MCP package
45
+ pnpm build:mcp
46
+
47
+ # Start MCP production server
48
+ pnpm start:mcp
49
+ ```
50
+
51
+ ## 🏗️ Project Structure
52
+
53
+ ```
54
+ .
55
+ ├── packages/
56
+ │ └── mcp/ # MCP implementation package
57
+ │ ├── src/ # Source code
58
+ │ └── .env # Environment configuration
59
+ ├── package.json # Root package.json
60
+ └── pnpm-workspace.yaml
61
+ ```
62
+
63
+ ## 🤝 Contributing
64
+
65
+ Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
66
+
67
+ ## 🌐 Social
68
+
69
+ - X/Twitter: [@kregenrek](https://x.com/kregenrek)
70
+ - Bluesky: [@kevinkern.dev](https://bsky.app/profile/kevinkern.dev)
71
+
72
+ ## 📝 License
73
+
74
+ [MIT License](https://github.com/instructa/ai-prompts/blob/main/LICENSE)
75
+
76
+ This repository is open-source under the MIT license. You're free to use, modify, and distribute it under those terms. Enjoy building!
package/package.json ADDED
@@ -0,0 +1 @@
1
+ {"name": "@iflow-mcp/instructa-ai-prompts-mcp", "version": "0.0.1", "description": "MCP server for managing and serving AI prompts", "main": "dist/src/index.js", "bin": {"iflow-mcp_instructa-ai-prompts-mcp": "./dist/src/index.js"}, "scripts": {"build": "cd packages/mcp && npx tsc", "start": "node ./dist/src/index.js"}, "dependencies": {"@modelcontextprotocol/sdk": "^1.6.1", "axios": "^1.8.1", "dotenv": "^16.4.7", "fuse.js": "^7.1.0", "h3": "^1.8.2", "zod": "^3.24.2"}, "devDependencies": {"@types/node": "^18.15.0", "typescript": "^4.9.5"}, "keywords": ["mcp", "model-context-protocol", "prompts", "ai"], "author": "instructa", "license": "ISC"}
@@ -0,0 +1 @@
1
+ API_BASE_URL=
@@ -0,0 +1 @@
1
+ { "name": "@iflow-mcp/instructa-ai-prompts-mcp", "version": "0.0.1", "description": "", "main": "index.js", "bin": { "iflow-mcp_instructa-ai-prompts-mcp": "./dist/src/index.js" }, "scripts": { "build": "tsc", "start": "node ./dist/src/index.js", "serve": "PORT=3001 npx --yes listhen ./src/app.ts", "inspector": "concurrently 'pnpm run serve' 'npx @modelcontextprotocol/inspector'" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.6.1", "axios": "^1.8.1", "dotenv": "^16.4.7", "fuse.js": "^7.1.0", "h3": "^1.8.2", "zod": "^3.24.2" }, "devDependencies": { "@types/node": "^18.15.0", "concurrently": "^9.1.2", "typescript": "^4.9.5" }, "keywords": [], "author": "", "license": "ISC", "packageManager": "pnpm@9.4.0" }
@@ -0,0 +1,9 @@
1
+ import axios from 'axios';
2
+ import 'dotenv/config';
3
+ export const client = axios.create({
4
+ baseURL: process.env.API_BASE_URL ?? '',
5
+ });
6
+ export function findRules(q) {
7
+ const params = { q };
8
+ return client.get('/rules', { params });
9
+ }
@@ -0,0 +1,11 @@
1
+ import { createApp, createRouter, defineEventHandler, toNodeListener } from 'h3';
2
+ import { createServer } from 'node:http';
3
+ import { createMcp } from './handlers/mcp';
4
+ const { onSse, onMsg } = createMcp();
5
+ export const app = createApp();
6
+ const router = createRouter();
7
+ router.get('/', defineEventHandler(() => ({ status: '✅' })));
8
+ router.get('/sse', onSse);
9
+ router.post('/messages', onMsg);
10
+ app.use(router);
11
+ createServer(toNodeListener(app));
@@ -0,0 +1,82 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
4
+ import { register as registerFindRuleTool } from "../tools/findrule";
5
+ const log = (...args) => process.env.NODE_ENV === "development" && console.info(...args);
6
+ // initialize the MCP server and register tools
7
+ export function initializeMcpServer() {
8
+ const server = new McpServer({
9
+ name: "mcp-prompt-finder",
10
+ version: "1.0.0",
11
+ }
12
+ // {
13
+ // capabilities: {
14
+ // tools: {
15
+ // demo: {
16
+ // title: 'Demo Tool',
17
+ // inputSchema: z.object({}).optional(),
18
+ // description: 'Just a demo tool',
19
+ // },
20
+ // },
21
+ // },
22
+ // }
23
+ );
24
+ registerFindRuleTool(server);
25
+ return server;
26
+ }
27
+ export const createMcp = () => {
28
+ const server = initializeMcpServer();
29
+ let transport;
30
+ const onSse = defineEventHandler(async (event) => {
31
+ const { res } = event.node;
32
+ transport = new SSEServerTransport("/messages", res);
33
+ await server.connect(transport);
34
+ const _onMsg = transport.onmessage;
35
+ const _onClose = transport.onclose;
36
+ const _onErr = transport.onerror;
37
+ // Send heartbeat every 5 seconds to keep the connection alive
38
+ const heartbeatInterval = setInterval(() => {
39
+ if (res.writable) {
40
+ res.write(":\n\n"); // Sending an empty comment to the client to keep the connection alive
41
+ }
42
+ }, 5000); // 5 seconds
43
+ transport.onmessage = (msg) => {
44
+ log(msg);
45
+ if (_onMsg)
46
+ _onMsg(msg);
47
+ };
48
+ transport.onclose = () => {
49
+ log("transport closed");
50
+ if (_onClose)
51
+ _onClose();
52
+ };
53
+ transport.onerror = (err) => {
54
+ log(err);
55
+ if (_onErr)
56
+ _onErr(err);
57
+ };
58
+ // handle client disconnect
59
+ res.on("close", async () => {
60
+ await server.close();
61
+ res.end();
62
+ clearInterval(heartbeatInterval);
63
+ log("disconnected");
64
+ });
65
+ ///
66
+ res.setHeader("Content-Type", "text/event-stream");
67
+ res.setHeader("Cache-Control", "no-cache");
68
+ res.setHeader("Connection", "keep-alive");
69
+ res.flushHeaders();
70
+ });
71
+ const onMsg = defineEventHandler(async (event) => {
72
+ const { req, res } = event.node;
73
+ log("<--", "Received message (post)");
74
+ if (transport?.handlePostMessage)
75
+ await transport.handlePostMessage(req, res);
76
+ log("<--", res.statusCode);
77
+ });
78
+ return {
79
+ onSse,
80
+ onMsg,
81
+ };
82
+ };
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { register as registerFindRuleTool } from "./tools/findrule.js";
5
+ async function main() {
6
+ const server = new McpServer({
7
+ name: "mcp-prompt-finder",
8
+ version: "1.0.0",
9
+ });
10
+ registerFindRuleTool(server);
11
+ const transport = new StdioServerTransport();
12
+ await server.connect(transport);
13
+ }
14
+ main().catch((error) => {
15
+ console.error("Fatal error in main():", error);
16
+ process.exit(1);
17
+ });
@@ -0,0 +1,97 @@
1
+ import { z } from 'zod';
2
+ import path from 'path';
3
+ import Fuse from 'fuse.js';
4
+ import { findRules } from '../api.js';
5
+ const RULE_NAME = 'findrule';
6
+ const RULE_DESCRIPTION = 'Retrieve a cursor AI rule based on the provided query.';
7
+ const findAndStreamPromptData = async (q) => {
8
+ // Try to fetch from API first
9
+ try {
10
+ const options = {
11
+ keys: ['name', 'description'],
12
+ threshold: 0.3,
13
+ };
14
+ const { data: list } = await findRules();
15
+ const fuse = new Fuse(list, options);
16
+ const result = fuse.search(q);
17
+ if (result.length > 0) {
18
+ return result[0].item;
19
+ }
20
+ }
21
+ catch (error) {
22
+ // Fall back to mock data if API is not available
23
+ const errorMessage = error instanceof Error ? error.message : String(error);
24
+ console.error('API unavailable, using mock data for testing:', errorMessage);
25
+ }
26
+ // Mock data for testing
27
+ const mockRule = {
28
+ name: 'Test Rule',
29
+ description: 'A test rule for demonstration',
30
+ type: 'test',
31
+ slug: 'test-rule',
32
+ author: {
33
+ name: 'Test Author',
34
+ url: 'https://example.com',
35
+ avatar: 'https://example.com/avatar.png'
36
+ },
37
+ prompts: [{
38
+ id: 'test-prompt',
39
+ description: 'Test prompt description',
40
+ globs: '*.ts',
41
+ content: 'This is a test prompt content for demonstration purposes.',
42
+ filePath: '/.cursor/rules/test.md'
43
+ }],
44
+ filePath: '/test/path'
45
+ };
46
+ return mockRule;
47
+ };
48
+ function createMsg(value) {
49
+ // Format the response as Markdown
50
+ const message = `
51
+ ### 🚀 File Ready: **${value.fileName}**
52
+
53
+ To save this file, follow these steps:
54
+
55
+ 1. Copy the content below.
56
+ 2. Create a new file in your workspace at:
57
+ \`${value.filePath}\`
58
+ 3. Paste the content into the file.
59
+
60
+ ---
61
+
62
+ **Content:**
63
+
64
+ \`\`\`markdown
65
+ ${value.fileData}
66
+ \`\`\`
67
+ `;
68
+ return message;
69
+ }
70
+ export const register = (server) => server.tool(RULE_NAME, RULE_DESCRIPTION, { q: z.string() }, async ({ q }) => {
71
+ const rule = await findAndStreamPromptData(q);
72
+ const [prompt] = rule.prompts;
73
+ const fileName = path.basename(prompt.filePath);
74
+ const filePath = path.join('.cursor', 'rules');
75
+ const metadata = [
76
+ `---`,
77
+ `# Specify the following for Cursor rules`,
78
+ `description: ${prompt.description}`,
79
+ `globs: ${prompt.globs}`,
80
+ `alwaysApply: true`,
81
+ `---`,
82
+ ]
83
+ .join('\n')
84
+ .concat('\n\n');
85
+ const title = `# ${prompt.id}\n\n`;
86
+ const content = [prompt.content].join('\n\n');
87
+ const fileData = metadata + title + content;
88
+ return {
89
+ content: [
90
+ {
91
+ type: 'text',
92
+ mimeType: 'text/markdown',
93
+ text: createMsg({ fileName, filePath, fileData }),
94
+ },
95
+ ],
96
+ };
97
+ });
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules/concurrently/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules/concurrently/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../concurrently/dist/bin/concurrently.js" "$@"
19
+ else
20
+ exec node "$basedir/../concurrently/dist/bin/concurrently.js" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules/concurrently/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules/concurrently/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/concurrently@9.1.2/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../concurrently/dist/bin/concurrently.js" "$@"
19
+ else
20
+ exec node "$basedir/../concurrently/dist/bin/concurrently.js" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
19
+ else
20
+ exec node "$basedir/../typescript/bin/tsc" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/typescript@4.9.5/node_modules:/app/auto-mcp-upload/data/10761/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
19
+ else
20
+ exec node "$basedir/../typescript/bin/tsserver" "$@"
21
+ fi
@@ -0,0 +1 @@
1
+ {"name": "@iflow-mcp/instructa-ai-prompts-mcp", "version": "0.0.1", "description": "", "main": "index.js", "bin": {"iflow-mcp_instructa-ai-prompts-mcp": "./dist/src/index.js"}, "scripts": {"build": "tsc", "start": "node ./dist/src/index.js", "serve": "PORT=3001 npx --yes listhen ./src/app.ts", "inspector": "concurrently 'pnpm run serve' 'npx @modelcontextprotocol/inspector'"}, "dependencies": {"@modelcontextprotocol/sdk": "^1.6.1", "axios": "^1.8.1", "dotenv": "^16.4.7", "fuse.js": "^7.1.0", "h3": "^1.8.2", "zod": "^3.24.2"}, "devDependencies": {"@types/node": "^18.15.0", "concurrently": "^9.1.2", "typescript": "^4.9.5"}, "keywords": [], "author": "", "license": "ISC", "packageManager": "pnpm@9.4.0"}