meebly-onboarding-mcp-server 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,31 @@
1
+ # Meebly Onboarding MCP Server
2
+
3
+ MCP Server for the Meebly AI platform, enabling agent and tool orchestration via the Model Context Protocol (MCP).
4
+
5
+ ## Tools
6
+
7
+ This server exposes a set of MCP tools for agent and workflow management. Tools include:
8
+
9
+ - `create_agent`: Create a new agent
10
+ - `create_action`: Create a new API action
11
+
12
+ Each tool has a defined input schema and returns structured results.
13
+
14
+ ## Setup
15
+
16
+ ```json
17
+ {
18
+ "type": "stdio",
19
+ "command": "npx",
20
+ "args": ["-y", "@meebly/meebly-onboarding-mcp-server"],
21
+ "env": {
22
+ "MEEBLY_API_KEY": "YOUR_API_KEY"
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## Environment Variables
28
+
29
+ Set the following environment variables:
30
+
31
+ - `MEEBLY_API_KEY` — API key to your environment
@@ -0,0 +1,13 @@
1
+ import axios from 'axios';
2
+ // For development, it can read from env var to point to local server
3
+ // In production, it will point to the deployed Meebly Backend because the env var will be undefined
4
+ const baseUrl = (process.env.MEEBLY_BACKEND_URL || 'https://api.meebly.ai') + '/v1';
5
+ // Client will set
6
+ const apiKey = process.env.MEEBLY_API_KEY || '';
7
+ export const httpClient = axios.create({
8
+ baseURL: baseUrl,
9
+ validateStatus: () => true, // never throw when not 2XX
10
+ headers: {
11
+ 'X-API-Key': apiKey,
12
+ },
13
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Helper function to maintain consistent tool return structure for success, failure, and error cases.
3
+ */
4
+ export function toolSuccess(response, structuredContent) {
5
+ return toolReturn(`Operation performed successfully.\n${JSON.stringify(response.data, null, 2)}`, structuredContent);
6
+ }
7
+ export function toolFailure(response) {
8
+ return toolReturn(`Operation failed. Status: ${response.status}\nResponse: ${JSON.stringify(response.data, null, 2)}`);
9
+ }
10
+ export function toolError(error) {
11
+ return toolReturn(`Error occurred while performing operation: ${error}`);
12
+ }
13
+ // Helper function to format tool return messages in proper structure
14
+ function toolReturn(message, structuredContent) {
15
+ return {
16
+ content: [
17
+ {
18
+ type: 'text',
19
+ text: message,
20
+ },
21
+ ],
22
+ structuredContent: structuredContent,
23
+ };
24
+ }
@@ -0,0 +1,27 @@
1
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ // Import all tools and resources
4
+ import * as tools from './tools/index.js';
5
+ import * as resources from './resources/index.js';
6
+ // Create the MCP server instance
7
+ const server = new McpServer({
8
+ name: 'meebly-onboarding-mcp-server',
9
+ version: '0.0.1',
10
+ });
11
+ // Register the tools
12
+ Object.values(tools).forEach((tool) => {
13
+ server.registerTool(tool.name, {
14
+ description: tool.description,
15
+ inputSchema: tool.inputSchema,
16
+ outputSchema: tool.outputSchema,
17
+ }, tool.handler);
18
+ });
19
+ // Register the resources
20
+ Object.values(resources).forEach((resource) => {
21
+ server.registerResource(resource.name, resource.uri, resource.metadata, resource.read);
22
+ });
23
+ // Start listening over stdio
24
+ const transport = new StdioServerTransport();
25
+ await server.connect(transport);
26
+ // Keep process alive
27
+ process.stdin.resume();
@@ -0,0 +1,45 @@
1
+ import { V1ActionDataSchema } from '../../../src/utils/validation.js';
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ const actionJsonSchema = zodToJsonSchema(V1ActionDataSchema, 'V1ActionDataSchema');
4
+ const responseSchema = {
5
+ type: 'object',
6
+ properties: {
7
+ status: {
8
+ type: 'string',
9
+ description: 'Result status',
10
+ },
11
+ agent: actionJsonSchema,
12
+ },
13
+ required: ['status', 'agent'],
14
+ };
15
+ /**
16
+ * Resource describing the createAgent POST endpoint
17
+ */
18
+ export const createActionEndpointResource = {
19
+ name: 'createActionEndpoint',
20
+ uri: 'api://meebly/action/create',
21
+ metadata: {
22
+ description: 'Describes the POST /action endpoint used to create new actions',
23
+ title: 'Create Action Endpoint',
24
+ },
25
+ read: async () => {
26
+ return {
27
+ contents: [
28
+ {
29
+ uri: 'api://meebly/action/create',
30
+ text: `
31
+ POST /action
32
+
33
+ Creates a new action.
34
+
35
+ Request body schema (JSON Schema):
36
+ ${JSON.stringify(actionJsonSchema, null, 2)}
37
+
38
+ Response schema (JSON Schema):
39
+ ${JSON.stringify(responseSchema, null, 2)}
40
+ `.trim(),
41
+ },
42
+ ],
43
+ };
44
+ },
45
+ };
@@ -0,0 +1,45 @@
1
+ import { AgentDataSchema } from '../../../src/utils/validation.js';
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ const agentJsonSchema = zodToJsonSchema(AgentDataSchema, 'AgentDataSchema');
4
+ const responseSchema = {
5
+ type: 'object',
6
+ properties: {
7
+ status: {
8
+ type: 'string',
9
+ description: 'Result status',
10
+ },
11
+ agent: agentJsonSchema,
12
+ },
13
+ required: ['status', 'agent'],
14
+ };
15
+ /**
16
+ * Resource describing the createAgent POST endpoint
17
+ */
18
+ export const createAgentEndpointResource = {
19
+ name: 'createAgentEndpoint',
20
+ uri: 'api://meebly/agent/create',
21
+ metadata: {
22
+ description: 'Describes the POST /agent endpoint used to create new agents',
23
+ title: 'Create Agent Endpoint',
24
+ },
25
+ read: async () => {
26
+ return {
27
+ contents: [
28
+ {
29
+ uri: 'api://meebly/agent/create',
30
+ text: `
31
+ POST /agent
32
+
33
+ Creates a new agent.
34
+
35
+ Request body schema (JSON Schema):
36
+ ${JSON.stringify(agentJsonSchema, null, 2)}
37
+
38
+ Response schema (JSON Schema):
39
+ ${JSON.stringify(responseSchema, null, 2)}
40
+ `.trim(),
41
+ },
42
+ ],
43
+ };
44
+ },
45
+ };
@@ -0,0 +1,3 @@
1
+ export { createActionEndpointResource } from './createActionEndpoint.js';
2
+ export { createAgentEndpointResource } from './createAgentEndpoint.js';
3
+ // add new resources here as you create them
@@ -0,0 +1,31 @@
1
+ import { V1ActionDataSchema } from '../../../src/utils/validation.js';
2
+ import { httpClient } from '../helpers/httpClient.js';
3
+ import { toolSuccess, toolFailure, toolError } from '../helpers/toolHelper.js';
4
+ import { z } from 'zod';
5
+ const CreateActionOutputSchema = z.object({
6
+ id: z.string().describe('The unique identifier of the created action'),
7
+ name: z.string().describe('The name of the created action'),
8
+ });
9
+ export const CreateActionTool = {
10
+ name: 'create_action',
11
+ description: 'Create a new action using the POST /action endpoint',
12
+ inputSchema: V1ActionDataSchema,
13
+ outputSchema: CreateActionOutputSchema,
14
+ handler: async (actionData) => {
15
+ const createData = V1ActionDataSchema.parse(actionData);
16
+ try {
17
+ const response = await httpClient.post('/action', createData);
18
+ if (response.status !== 201) {
19
+ return toolFailure(response);
20
+ }
21
+ const outputData = {
22
+ id: response.data.id,
23
+ name: response.data.operationName,
24
+ };
25
+ return toolSuccess(response, outputData);
26
+ }
27
+ catch (error) {
28
+ return toolError(error);
29
+ }
30
+ },
31
+ };
@@ -0,0 +1,31 @@
1
+ import { AgentDataSchema } from '../../../src/utils/validation.js';
2
+ import { httpClient } from '../helpers/httpClient.js';
3
+ import { toolSuccess, toolFailure, toolError } from '../helpers/toolHelper.js';
4
+ import { z } from 'zod';
5
+ const CreateAgentOutputSchema = z.object({
6
+ id: z.string().describe('The unique identifier of the created agent'),
7
+ name: z.string().describe('The name of the created agent'),
8
+ });
9
+ export const CreateAgentTool = {
10
+ name: 'create_agent',
11
+ description: 'Create a new agent using the POST /agent endpoint',
12
+ inputSchema: AgentDataSchema,
13
+ outputSchema: CreateAgentOutputSchema,
14
+ handler: async (agentData) => {
15
+ const createData = AgentDataSchema.parse(agentData);
16
+ try {
17
+ const response = await httpClient.post('/agent', createData);
18
+ if (response.status !== 201) {
19
+ return toolFailure(response);
20
+ }
21
+ const outputData = {
22
+ id: response.data.id,
23
+ name: response.data.name,
24
+ };
25
+ return toolSuccess(response, outputData);
26
+ }
27
+ catch (error) {
28
+ return toolError(error);
29
+ }
30
+ },
31
+ };
@@ -0,0 +1,3 @@
1
+ export { CreateAgentTool } from './createAgent.js';
2
+ export { CreateActionTool } from './createAction.js';
3
+ // add new tools here as you create them
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Application constants
3
+ */
4
+ // Mastra storage and vector IDs
5
+ export { MASTRA_STORAGE_IDS } from './mastraIds.js';
6
+ // Supabase error codes
7
+ export const SUPABASE_ERROR_CODES = {
8
+ NOT_FOUND: 'PGRST116',
9
+ DUPLICATE_KEY: '23505',
10
+ FOREIGN_KEY_VIOLATION: '23503',
11
+ NOT_NULL_VIOLATION: '23502',
12
+ };
13
+ // HTTP status codes
14
+ export const HTTP_STATUS = {
15
+ OK: 200,
16
+ CREATED: 201,
17
+ BAD_REQUEST: 400,
18
+ UNAUTHORIZED: 401,
19
+ FORBIDDEN: 403,
20
+ NOT_FOUND: 404,
21
+ CONFLICT: 409,
22
+ INTERNAL_SERVER_ERROR: 500,
23
+ BAD_GATEWAY: 502,
24
+ TOO_MANY_REQUESTS: 429,
25
+ };
26
+ // Auth types
27
+ export const STATIC_AUTH_TYPES = {
28
+ BEARER: 'bearer',
29
+ API_KEY: 'api-key',
30
+ ACCESS_TOKEN: 'access-token',
31
+ };
32
+ // Content types
33
+ export const CONTENT_TYPES = {
34
+ JSON: 'application/json',
35
+ FORM_DATA: 'multipart/form-data',
36
+ FORM_URLENCODED: 'application/x-www-form-urlencoded',
37
+ TEXT_PLAIN: 'text/plain',
38
+ };
39
+ // HTTP methods
40
+ export const HTTP_METHODS = {
41
+ GET: 'GET',
42
+ POST: 'POST',
43
+ PUT: 'PUT',
44
+ DELETE: 'DELETE',
45
+ PATCH: 'PATCH',
46
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Mastra Storage and Vector Store IDs
3
+ *
4
+ * Centralized IDs for Mastra storage and vector instances.
5
+ * These IDs are required by Mastra v1 for tracking and managing
6
+ * storage instances within the framework.
7
+ */
8
+ export const MASTRA_STORAGE_IDS = {
9
+ /** Main PostgreSQL storage instance */
10
+ POSTGRES_STORE: 'meebly-postgres-store',
11
+ /** PostgreSQL vector store instance */
12
+ PG_VECTOR: 'meebly-pg-vector',
13
+ };
@@ -0,0 +1,104 @@
1
+ import { HTTP_STATUS } from '../constants/index.js';
2
+ /**
3
+ * Custom error class for API errors with error codes
4
+ */
5
+ export class ApiError extends Error {
6
+ statusCode;
7
+ code;
8
+ details;
9
+ constructor(message, statusCode = HTTP_STATUS.INTERNAL_SERVER_ERROR, details, code) {
10
+ super(message);
11
+ this.name = 'ApiError';
12
+ this.statusCode = statusCode;
13
+ this.details = details;
14
+ this.code = code || ApiError.generateErrorCode(statusCode);
15
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
16
+ if (Error.captureStackTrace) {
17
+ Error.captureStackTrace(this, ApiError);
18
+ }
19
+ }
20
+ /**
21
+ * Generate error code from HTTP status code
22
+ */
23
+ static generateErrorCode(statusCode) {
24
+ const codeMap = {
25
+ 400: 'BAD_REQUEST',
26
+ 401: 'UNAUTHORIZED',
27
+ 403: 'FORBIDDEN',
28
+ 404: 'NOT_FOUND',
29
+ 409: 'CONFLICT',
30
+ 422: 'VALIDATION_ERROR',
31
+ 429: 'TOO_MANY_REQUESTS',
32
+ 500: 'INTERNAL_SERVER_ERROR',
33
+ 503: 'SERVICE_UNAVAILABLE',
34
+ };
35
+ return codeMap[statusCode] || 'UNKNOWN_ERROR';
36
+ }
37
+ }
38
+ /**
39
+ * Creates a standardized error response object
40
+ * @param error - The error object or message
41
+ * @param statusCode - HTTP status code
42
+ * @returns Standardized error response
43
+ */
44
+ export function createErrorResponse(error, statusCode = HTTP_STATUS.INTERNAL_SERVER_ERROR) {
45
+ if (error instanceof ApiError) {
46
+ return {
47
+ error: error.message,
48
+ statusCode: error.statusCode,
49
+ details: error.details,
50
+ };
51
+ }
52
+ if (error instanceof Error) {
53
+ return {
54
+ error: error.message,
55
+ statusCode,
56
+ };
57
+ }
58
+ return {
59
+ error: typeof error === 'string' ? error : 'An unknown error occurred',
60
+ statusCode,
61
+ };
62
+ }
63
+ /**
64
+ * Handles async route errors for Express
65
+ * @param fn - Async route handler function
66
+ * @returns Express middleware function
67
+ */
68
+ export function asyncErrorHandler(fn) {
69
+ return (req, res, next) => {
70
+ Promise.resolve(fn(req, res, next)).catch(next);
71
+ };
72
+ }
73
+ /**
74
+ * Express error middleware - Returns standardized error format
75
+ * @param err - Error object
76
+ * @param req - Express request
77
+ * @param res - Express response
78
+ * @param next - Express next function
79
+ */
80
+ export function errorMiddleware(err, _req, res, _next) {
81
+ // Only log errors in non-test environments to reduce console noise during testing
82
+ if (process.env.NODE_ENV !== 'test') {
83
+ console.error('Error:', err);
84
+ }
85
+ // Extract error details
86
+ const statusCode = err.statusCode || err.status || HTTP_STATUS.INTERNAL_SERVER_ERROR;
87
+ const message = err.message || 'An unexpected error occurred';
88
+ const code = err.code || (err instanceof ApiError ? err.code : 'INTERNAL_SERVER_ERROR');
89
+ const details = err.details;
90
+ // Build standardized error response
91
+ const response = {
92
+ success: false,
93
+ error: {
94
+ code,
95
+ message,
96
+ ...(details && { details }),
97
+ ...(process.env.NODE_ENV === 'test' && { stack: err.stack }),
98
+ },
99
+ meta: {
100
+ timestamp: new Date().toISOString(),
101
+ },
102
+ };
103
+ res.status(statusCode).json(response);
104
+ }