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 +31 -0
- package/dist/mcp-server/src/helpers/httpClient.js +13 -0
- package/dist/mcp-server/src/helpers/toolHelper.js +24 -0
- package/dist/mcp-server/src/index.js +27 -0
- package/dist/mcp-server/src/resources/createActionEndpoint.js +45 -0
- package/dist/mcp-server/src/resources/createAgentEndpoint.js +45 -0
- package/dist/mcp-server/src/resources/index.js +3 -0
- package/dist/mcp-server/src/tools/createAction.js +31 -0
- package/dist/mcp-server/src/tools/createAgent.js +31 -0
- package/dist/mcp-server/src/tools/index.js +3 -0
- package/dist/src/constants/index.js +46 -0
- package/dist/src/constants/mastraIds.js +13 -0
- package/dist/src/utils/errorUtils.js +104 -0
- package/dist/src/utils/validation.js +724 -0
- package/package.json +15 -0
- package/src/helpers/httpClient.ts +17 -0
- package/src/helpers/toolHelper.ts +40 -0
- package/src/index.ts +42 -0
- package/src/resources/createActionEndpoint.ts +51 -0
- package/src/resources/createAgentEndpoint.ts +50 -0
- package/src/resources/index.ts +3 -0
- package/src/tools/createAction.ts +36 -0
- package/src/tools/createAgent.ts +36 -0
- package/src/tools/index.ts +3 -0
- package/tsconfig.json +12 -0
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,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,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
|
+
}
|