0nmcp 1.3.0 → 1.4.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.
- package/cli.js +101 -1
- package/index.js +8 -332
- package/lib/badges.json +1 -1
- package/lib/stats.json +4 -2
- package/package.json +32 -9
- package/server.js +272 -0
- package/tools.js +419 -0
- package/workflow.js +589 -0
package/cli.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
8
|
* npx 0nmcp Start MCP server (stdio)
|
|
9
|
+
* npx 0nmcp serve Start HTTP server (REST + MCP + webhooks)
|
|
10
|
+
* npx 0nmcp run <wf> Run a .0n workflow from CLI
|
|
9
11
|
* npx 0nmcp init Initialize ~/.0n directory
|
|
10
12
|
* npx 0nmcp connect Interactive connection setup
|
|
11
13
|
* npx 0nmcp list List connected services
|
|
@@ -68,12 +70,22 @@ async function main() {
|
|
|
68
70
|
console.log(`
|
|
69
71
|
${c.bright}Usage:${c.reset}
|
|
70
72
|
|
|
71
|
-
${c.cyan}npx 0nmcp${c.reset} Start MCP server (for Claude Desktop)
|
|
73
|
+
${c.cyan}npx 0nmcp${c.reset} Start MCP server (stdio, for Claude Desktop)
|
|
74
|
+
${c.cyan}npx 0nmcp serve${c.reset} Start HTTP server (REST + MCP + webhooks)
|
|
75
|
+
${c.cyan}npx 0nmcp run <wf>${c.reset} Run a .0n workflow from CLI
|
|
72
76
|
${c.cyan}npx 0nmcp init${c.reset} Initialize ~/.0n directory
|
|
73
77
|
${c.cyan}npx 0nmcp connect${c.reset} Interactive connection setup
|
|
74
78
|
${c.cyan}npx 0nmcp list${c.reset} List connected services
|
|
75
79
|
${c.cyan}npx 0nmcp migrate${c.reset} Migrate from ~/.0nmcp to ~/.0n
|
|
76
80
|
|
|
81
|
+
${c.bright}Serve options:${c.reset}
|
|
82
|
+
|
|
83
|
+
${c.cyan}npx 0nmcp serve --port 3000 --host 0.0.0.0${c.reset}
|
|
84
|
+
|
|
85
|
+
${c.bright}Run options:${c.reset}
|
|
86
|
+
|
|
87
|
+
${c.cyan}npx 0nmcp run invoice-notify --input customer_email=test@x.com --input amount=100${c.reset}
|
|
88
|
+
|
|
77
89
|
${c.bright}Configure Claude Desktop:${c.reset}
|
|
78
90
|
|
|
79
91
|
Add to your claude_desktop_config.json:
|
|
@@ -117,6 +129,85 @@ ${c.bright}Links:${c.reset}
|
|
|
117
129
|
return;
|
|
118
130
|
}
|
|
119
131
|
|
|
132
|
+
// Serve (HTTP server)
|
|
133
|
+
if (command === 'serve') {
|
|
134
|
+
console.log(BANNER);
|
|
135
|
+
const port = getFlag(args, '--port', 3000);
|
|
136
|
+
const host = getFlag(args, '--host', '0.0.0.0');
|
|
137
|
+
|
|
138
|
+
console.log(`${c.bright}Starting HTTP server...${c.reset}\n`);
|
|
139
|
+
|
|
140
|
+
const { startServer } = await import('./server.js');
|
|
141
|
+
await startServer({ port: Number(port), host: String(host) });
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Run (execute a workflow from CLI)
|
|
146
|
+
if (command === 'run') {
|
|
147
|
+
const workflowName = args[1];
|
|
148
|
+
if (!workflowName) {
|
|
149
|
+
console.log(`${c.red}Usage: npx 0nmcp run <workflow-name> [--input key=value]${c.reset}`);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Parse --input flags
|
|
154
|
+
const inputs = {};
|
|
155
|
+
for (let i = 2; i < args.length; i++) {
|
|
156
|
+
if (args[i] === '--input' && args[i + 1]) {
|
|
157
|
+
const [key, ...valueParts] = args[i + 1].split('=');
|
|
158
|
+
const value = valueParts.join('=');
|
|
159
|
+
// Auto-type: numbers and booleans
|
|
160
|
+
if (value === 'true') inputs[key] = true;
|
|
161
|
+
else if (value === 'false') inputs[key] = false;
|
|
162
|
+
else if (!isNaN(value) && value !== '') inputs[key] = Number(value);
|
|
163
|
+
else inputs[key] = value;
|
|
164
|
+
i++;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log(`${c.bright}Running workflow: ${c.cyan}${workflowName}${c.reset}`);
|
|
169
|
+
if (Object.keys(inputs).length > 0) {
|
|
170
|
+
console.log(`${c.bright}Inputs:${c.reset}`, JSON.stringify(inputs, null, 2));
|
|
171
|
+
}
|
|
172
|
+
console.log('');
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const { ConnectionManager } = await import('./connections.js');
|
|
176
|
+
const { WorkflowRunner } = await import('./workflow.js');
|
|
177
|
+
|
|
178
|
+
const connections = new ConnectionManager();
|
|
179
|
+
const runner = new WorkflowRunner(connections);
|
|
180
|
+
const result = await runner.run({ workflowPath: workflowName, inputs });
|
|
181
|
+
|
|
182
|
+
if (result.success) {
|
|
183
|
+
console.log(`${c.green}${c.bright}Workflow completed successfully${c.reset}`);
|
|
184
|
+
} else {
|
|
185
|
+
console.log(`${c.red}${c.bright}Workflow failed${c.reset}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log(`\n${c.bright}Execution ID:${c.reset} ${result.executionId}`);
|
|
189
|
+
console.log(`${c.bright}Steps:${c.reset} ${result.stepsSuccessful}/${result.stepsExecuted} successful`);
|
|
190
|
+
console.log(`${c.bright}Duration:${c.reset} ${result.duration}ms`);
|
|
191
|
+
|
|
192
|
+
if (result.outputs && Object.keys(result.outputs).length > 0) {
|
|
193
|
+
console.log(`\n${c.bright}Outputs:${c.reset}`);
|
|
194
|
+
console.log(JSON.stringify(result.outputs, null, 2));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (result.errors.length > 0) {
|
|
198
|
+
console.log(`\n${c.red}${c.bright}Errors:${c.reset}`);
|
|
199
|
+
for (const err of result.errors) {
|
|
200
|
+
console.log(` ${c.red}●${c.reset} ${err.service}.${err.action}: ${err.error}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
process.exit(result.success ? 0 : 1);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
console.log(`${c.red}Error: ${err.message}${c.reset}`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
120
211
|
// Migrate
|
|
121
212
|
if (command === 'migrate') {
|
|
122
213
|
console.log(BANNER);
|
|
@@ -132,6 +223,15 @@ ${c.bright}Links:${c.reset}
|
|
|
132
223
|
process.exit(1);
|
|
133
224
|
}
|
|
134
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Get a CLI flag value: --flag value
|
|
228
|
+
*/
|
|
229
|
+
function getFlag(args, flag, defaultValue) {
|
|
230
|
+
const idx = args.indexOf(flag);
|
|
231
|
+
if (idx !== -1 && args[idx + 1]) return args[idx + 1];
|
|
232
|
+
return defaultValue;
|
|
233
|
+
}
|
|
234
|
+
|
|
135
235
|
function initDotOn() {
|
|
136
236
|
const dirs = [
|
|
137
237
|
DOT_ON_DIR,
|
package/index.js
CHANGED
|
@@ -21,362 +21,38 @@
|
|
|
21
21
|
|
|
22
22
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
23
23
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
24
|
-
import { z } from "zod";
|
|
25
24
|
|
|
26
|
-
import { SERVICE_CATALOG, listServices, getService } from "./catalog.js";
|
|
27
25
|
import { ConnectionManager } from "./connections.js";
|
|
28
26
|
import { Orchestrator } from "./orchestrator.js";
|
|
27
|
+
import { WorkflowRunner } from "./workflow.js";
|
|
28
|
+
import { registerAllTools } from "./tools.js";
|
|
29
29
|
import { registerCrmTools } from "./crm/index.js";
|
|
30
30
|
|
|
31
31
|
// ── Initialize ─────────────────────────────────────────────
|
|
32
32
|
const connections = new ConnectionManager();
|
|
33
33
|
const orchestrator = new Orchestrator(connections);
|
|
34
|
+
const workflowRunner = new WorkflowRunner(connections);
|
|
34
35
|
|
|
35
36
|
const server = new McpServer({
|
|
36
37
|
name: "0nMCP",
|
|
37
|
-
version: "1.
|
|
38
|
+
version: "1.4.0",
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
// ============================================================
|
|
41
|
-
//
|
|
42
|
+
// REGISTER ALL TOOLS
|
|
42
43
|
// ============================================================
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
server.tool(
|
|
46
|
-
"execute",
|
|
47
|
-
`Execute any task using connected services. The AI orchestrator automatically:
|
|
48
|
-
1. Parses your intent from natural language
|
|
49
|
-
2. Finds the best services to use
|
|
50
|
-
3. Creates an execution plan
|
|
51
|
-
4. Executes all necessary API calls
|
|
52
|
-
5. Returns results
|
|
53
|
-
|
|
54
|
-
Examples:
|
|
55
|
-
- "Send an email to john@example.com about the meeting tomorrow"
|
|
56
|
-
- "Create a Stripe customer for sarah@test.com"
|
|
57
|
-
- "Post to #sales on Slack: We just closed a deal!"
|
|
58
|
-
- "Get my Stripe balance"
|
|
59
|
-
- "Add a record to Airtable: Name=John, Status=Active"
|
|
60
|
-
- "Send an SMS to +1234567890: Your order shipped"
|
|
61
|
-
- "Create a GitHub issue: Bug in login page"`,
|
|
62
|
-
{
|
|
63
|
-
task: z.string().describe("Natural language description of what you want to accomplish"),
|
|
64
|
-
},
|
|
65
|
-
async ({ task }) => {
|
|
66
|
-
const result = await orchestrator.execute(task);
|
|
67
|
-
|
|
68
|
-
if (result.success) {
|
|
69
|
-
return {
|
|
70
|
-
content: [{
|
|
71
|
-
type: "text",
|
|
72
|
-
text: JSON.stringify({
|
|
73
|
-
status: "completed",
|
|
74
|
-
message: result.message,
|
|
75
|
-
steps_executed: result.details?.stepsExecuted || 0,
|
|
76
|
-
steps_successful: result.details?.stepsSuccessful || 0,
|
|
77
|
-
duration_ms: result.details?.duration || 0,
|
|
78
|
-
services_used: result.details?.servicesUsed || [],
|
|
79
|
-
plan: result.details?.plan || [],
|
|
80
|
-
}, null, 2),
|
|
81
|
-
}],
|
|
82
|
-
};
|
|
83
|
-
} else {
|
|
84
|
-
return {
|
|
85
|
-
content: [{
|
|
86
|
-
type: "text",
|
|
87
|
-
text: JSON.stringify({
|
|
88
|
-
status: "failed",
|
|
89
|
-
error: result.error,
|
|
90
|
-
suggestion: result.suggestion,
|
|
91
|
-
connected_services: result.connected_services,
|
|
92
|
-
}, null, 2),
|
|
93
|
-
}],
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
// ─── connect_service ───────────────────────────────────────
|
|
100
|
-
server.tool(
|
|
101
|
-
"connect_service",
|
|
102
|
-
`Connect a service so the orchestrator can use it. Each service requires specific credentials.
|
|
103
|
-
|
|
104
|
-
Examples:
|
|
105
|
-
- Stripe: { "apiKey": "sk_live_..." }
|
|
106
|
-
- SendGrid: { "apiKey": "SG..." }
|
|
107
|
-
- Twilio: { "accountSid": "AC...", "authToken": "..." }
|
|
108
|
-
- Slack: { "botToken": "xoxb-..." }
|
|
109
|
-
- OpenAI: { "apiKey": "sk-..." }
|
|
110
|
-
- GitHub: { "token": "ghp_..." }
|
|
111
|
-
- Notion: { "apiKey": "ntn_..." }
|
|
112
|
-
- Airtable: { "apiKey": "pat..." }
|
|
113
|
-
- CRM: { "access_token": "..." }
|
|
114
|
-
- HubSpot: { "accessToken": "..." }
|
|
115
|
-
- Shopify: { "accessToken": "...", "store": "mystore" }
|
|
116
|
-
- Supabase: { "apiKey": "...", "projectRef": "..." }
|
|
117
|
-
- Gmail: { "access_token": "..." }
|
|
118
|
-
- Google Sheets: { "access_token": "..." }
|
|
119
|
-
- Google Drive: { "access_token": "..." }
|
|
120
|
-
- Jira: { "email": "...", "apiToken": "...", "domain": "mycompany" }
|
|
121
|
-
- Zendesk: { "email": "...", "apiToken": "...", "subdomain": "mycompany" }
|
|
122
|
-
- Mailchimp: { "apiKey": "...-us21" }
|
|
123
|
-
- Zoom: { "access_token": "..." }
|
|
124
|
-
- Microsoft 365: { "access_token": "..." }
|
|
125
|
-
- MongoDB: { "apiKey": "...", "appId": "..." }`,
|
|
126
|
-
{
|
|
127
|
-
service: z.string().describe("Service key (e.g., stripe, sendgrid, twilio, slack, crm, github, notion, airtable, openai, shopify, hubspot, supabase, discord, linear, resend, calendly, google_calendar, gmail, google_sheets, google_drive, jira, zendesk, mailchimp, zoom, microsoft, mongodb)"),
|
|
128
|
-
credentials: z.record(z.string()).describe("Service credentials as key-value pairs"),
|
|
129
|
-
},
|
|
130
|
-
async ({ service, credentials }) => {
|
|
131
|
-
const result = connections.connect(service, credentials);
|
|
132
|
-
|
|
133
|
-
if (result.success) {
|
|
134
|
-
return {
|
|
135
|
-
content: [{
|
|
136
|
-
type: "text",
|
|
137
|
-
text: JSON.stringify({
|
|
138
|
-
status: "connected",
|
|
139
|
-
service: result.service.name,
|
|
140
|
-
capabilities: result.service.capabilities,
|
|
141
|
-
message: `Connected to ${result.service.name}. You now have ${result.service.capabilities} capabilities available.`,
|
|
142
|
-
}, null, 2),
|
|
143
|
-
}],
|
|
144
|
-
};
|
|
145
|
-
} else {
|
|
146
|
-
return {
|
|
147
|
-
content: [{
|
|
148
|
-
type: "text",
|
|
149
|
-
text: JSON.stringify({ status: "failed", error: result.error }, null, 2),
|
|
150
|
-
}],
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
// ─── disconnect_service ────────────────────────────────────
|
|
157
|
-
server.tool(
|
|
158
|
-
"disconnect_service",
|
|
159
|
-
"Disconnect a connected service. Removes stored credentials.",
|
|
160
|
-
{
|
|
161
|
-
service: z.string().describe("Service key to disconnect (e.g., stripe, sendgrid)"),
|
|
162
|
-
},
|
|
163
|
-
async ({ service }) => {
|
|
164
|
-
const result = connections.disconnect(service);
|
|
165
|
-
return {
|
|
166
|
-
content: [{
|
|
167
|
-
type: "text",
|
|
168
|
-
text: JSON.stringify({
|
|
169
|
-
status: result.success ? "disconnected" : "failed",
|
|
170
|
-
error: result.error,
|
|
171
|
-
}, null, 2),
|
|
172
|
-
}],
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
// ─── list_connections ──────────────────────────────────────
|
|
178
|
-
server.tool(
|
|
179
|
-
"list_connections",
|
|
180
|
-
"List all connected services, their types, and capability counts.",
|
|
181
|
-
{},
|
|
182
|
-
async () => {
|
|
183
|
-
const connected = connections.list();
|
|
184
|
-
|
|
185
|
-
if (connected.length === 0) {
|
|
186
|
-
return {
|
|
187
|
-
content: [{
|
|
188
|
-
type: "text",
|
|
189
|
-
text: JSON.stringify({
|
|
190
|
-
count: 0,
|
|
191
|
-
services: [],
|
|
192
|
-
message: "No services connected. Use connect_service to add integrations.",
|
|
193
|
-
}, null, 2),
|
|
194
|
-
}],
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
content: [{
|
|
200
|
-
type: "text",
|
|
201
|
-
text: JSON.stringify({
|
|
202
|
-
count: connected.length,
|
|
203
|
-
services: connected,
|
|
204
|
-
}, null, 2),
|
|
205
|
-
}],
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
// ─── list_available_services ───────────────────────────────
|
|
211
|
-
server.tool(
|
|
212
|
-
"list_available_services",
|
|
213
|
-
"List all services that can be connected, grouped by category.",
|
|
214
|
-
{},
|
|
215
|
-
async () => {
|
|
216
|
-
const services = listServices();
|
|
217
|
-
const connected = new Set(connections.keys());
|
|
218
|
-
|
|
219
|
-
// Group by type
|
|
220
|
-
const grouped = {};
|
|
221
|
-
for (const svc of services) {
|
|
222
|
-
if (!grouped[svc.type]) grouped[svc.type] = [];
|
|
223
|
-
grouped[svc.type].push({
|
|
224
|
-
key: svc.key,
|
|
225
|
-
name: svc.name,
|
|
226
|
-
description: svc.description,
|
|
227
|
-
capabilities: svc.capabilityCount,
|
|
228
|
-
authType: svc.authType,
|
|
229
|
-
credentialKeys: svc.credentialKeys,
|
|
230
|
-
connected: connected.has(svc.key),
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
content: [{
|
|
236
|
-
type: "text",
|
|
237
|
-
text: JSON.stringify({
|
|
238
|
-
total: services.length,
|
|
239
|
-
connected: connected.size,
|
|
240
|
-
services: grouped,
|
|
241
|
-
}, null, 2),
|
|
242
|
-
}],
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
// ─── get_service_info ──────────────────────────────────────
|
|
248
|
-
server.tool(
|
|
249
|
-
"get_service_info",
|
|
250
|
-
"Get detailed information about a specific service — capabilities, endpoints, and required credentials.",
|
|
251
|
-
{
|
|
252
|
-
service: z.string().describe("Service key (e.g., stripe, crm)"),
|
|
253
|
-
},
|
|
254
|
-
async ({ service }) => {
|
|
255
|
-
const catalog = getService(service);
|
|
256
|
-
if (!catalog) {
|
|
257
|
-
return {
|
|
258
|
-
content: [{
|
|
259
|
-
type: "text",
|
|
260
|
-
text: JSON.stringify({ error: `Unknown service: ${service}`, available: listServices().map(s => s.key) }, null, 2),
|
|
261
|
-
}],
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
content: [{
|
|
267
|
-
type: "text",
|
|
268
|
-
text: JSON.stringify({
|
|
269
|
-
key: service,
|
|
270
|
-
name: catalog.name,
|
|
271
|
-
type: catalog.type,
|
|
272
|
-
description: catalog.description,
|
|
273
|
-
authType: catalog.authType,
|
|
274
|
-
credentialKeys: catalog.credentialKeys,
|
|
275
|
-
connected: connections.isConnected(service),
|
|
276
|
-
capabilities: catalog.capabilities,
|
|
277
|
-
endpoints: Object.entries(catalog.endpoints).map(([key, ep]) => ({
|
|
278
|
-
name: key,
|
|
279
|
-
method: ep.method,
|
|
280
|
-
path: ep.path,
|
|
281
|
-
})),
|
|
282
|
-
}, null, 2),
|
|
283
|
-
}],
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
// ─── api_call ──────────────────────────────────────────────
|
|
289
|
-
server.tool(
|
|
290
|
-
"api_call",
|
|
291
|
-
"Make a direct API call to any connected service. For advanced use when you need fine-grained control beyond the execute tool.",
|
|
292
|
-
{
|
|
293
|
-
service: z.string().describe("Service key (e.g., stripe, sendgrid)"),
|
|
294
|
-
endpoint: z.string().describe("Endpoint name from the service catalog"),
|
|
295
|
-
params: z.record(z.any()).optional().describe("Parameters for the API call"),
|
|
296
|
-
},
|
|
297
|
-
async ({ service, endpoint, params }) => {
|
|
298
|
-
const catalog = getService(service);
|
|
299
|
-
if (!catalog) {
|
|
300
|
-
return { content: [{ type: "text", text: JSON.stringify({ error: `Unknown service: ${service}` }, null, 2) }] };
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
const ep = catalog.endpoints[endpoint];
|
|
304
|
-
if (!ep) {
|
|
305
|
-
return {
|
|
306
|
-
content: [{
|
|
307
|
-
type: "text",
|
|
308
|
-
text: JSON.stringify({ error: `Unknown endpoint: ${endpoint}`, available: Object.keys(catalog.endpoints) }, null, 2),
|
|
309
|
-
}],
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const creds = connections.getCredentials(service);
|
|
314
|
-
if (!creds) {
|
|
315
|
-
return { content: [{ type: "text", text: JSON.stringify({ error: `Service ${service} not connected` }, null, 2) }] };
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
try {
|
|
319
|
-
let url = catalog.baseUrl + ep.path;
|
|
320
|
-
const allParams = { ...creds, ...(params || {}) };
|
|
321
|
-
|
|
322
|
-
// Substitute path params
|
|
323
|
-
url = url.replace(/\{(\w+)\}/g, (_, key) => allParams[key] || `{${key}}`);
|
|
324
|
-
|
|
325
|
-
const headers = catalog.authHeader(creds);
|
|
326
|
-
const options = { method: ep.method, headers };
|
|
327
|
-
|
|
328
|
-
if (ep.method !== "GET" && params) {
|
|
329
|
-
const contentType = ep.contentType || "application/json";
|
|
330
|
-
if (contentType === "application/x-www-form-urlencoded") {
|
|
331
|
-
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
332
|
-
const flat = {};
|
|
333
|
-
for (const [k, v] of Object.entries(params)) {
|
|
334
|
-
if (typeof v !== "object") flat[k] = String(v);
|
|
335
|
-
}
|
|
336
|
-
options.body = new URLSearchParams(flat).toString();
|
|
337
|
-
} else {
|
|
338
|
-
headers["Content-Type"] = "application/json";
|
|
339
|
-
options.body = JSON.stringify(params);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (ep.method === "GET" && params) {
|
|
344
|
-
const flat = {};
|
|
345
|
-
for (const [k, v] of Object.entries(params)) {
|
|
346
|
-
if (typeof v !== "object") flat[k] = String(v);
|
|
347
|
-
}
|
|
348
|
-
const qs = new URLSearchParams(flat).toString();
|
|
349
|
-
if (qs) url += (url.includes("?") ? "&" : "?") + qs;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const response = await fetch(url, options);
|
|
353
|
-
const data = await response.json().catch(() => ({ status: response.status, statusText: response.statusText }));
|
|
354
|
-
|
|
355
|
-
return {
|
|
356
|
-
content: [{
|
|
357
|
-
type: "text",
|
|
358
|
-
text: JSON.stringify({ success: response.ok, status: response.status, data }, null, 2),
|
|
359
|
-
}],
|
|
360
|
-
};
|
|
361
|
-
} catch (err) {
|
|
362
|
-
return { content: [{ type: "text", text: JSON.stringify({ error: err.message }, null, 2) }] };
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
);
|
|
45
|
+
registerAllTools(server, connections, orchestrator, workflowRunner);
|
|
366
46
|
|
|
367
47
|
// ============================================================
|
|
368
48
|
// SERVICE-SPECIFIC TOOLS
|
|
369
49
|
// ============================================================
|
|
370
50
|
|
|
371
|
-
|
|
51
|
+
import { z } from "zod";
|
|
372
52
|
registerCrmTools(server, z);
|
|
373
53
|
|
|
374
|
-
// Future: registerStripeTools(server, z);
|
|
375
|
-
// Future: registerSlackTools(server, z);
|
|
376
|
-
// Future: registerShopifyTools(server, z);
|
|
377
|
-
|
|
378
54
|
// ============================================================
|
|
379
|
-
// START SERVER
|
|
55
|
+
// START SERVER (stdio transport)
|
|
380
56
|
// ============================================================
|
|
381
57
|
|
|
382
58
|
const transport = new StdioServerTransport();
|
package/lib/badges.json
CHANGED
package/lib/stats.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-02-
|
|
2
|
+
"generated": "2026-02-15T00:13:31.784Z",
|
|
3
3
|
"catalogVersion": "1.2.2",
|
|
4
4
|
"services": 26,
|
|
5
5
|
"tools": 290,
|
|
@@ -791,5 +791,7 @@
|
|
|
791
791
|
"microsoft",
|
|
792
792
|
"mongodb"
|
|
793
793
|
],
|
|
794
|
-
"
|
|
794
|
+
"crmTools": 245,
|
|
795
|
+
"totalTools": 535,
|
|
796
|
+
"totalCapabilities": 693
|
|
795
797
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "0nmcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"mcpName": "io.github.0nork/0nMCP",
|
|
5
|
-
"description": "Universal AI API Orchestrator —
|
|
5
|
+
"description": "Universal AI API Orchestrator — 535 tools, 26 services, natural language interface. The most comprehensive MCP server available. Free and open source from 0nORK.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"types": "types/index.d.ts",
|
|
9
9
|
"bin": {
|
|
10
|
-
"0nmcp": "
|
|
10
|
+
"0nmcp": "cli.js"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
@@ -34,10 +34,20 @@
|
|
|
34
34
|
},
|
|
35
35
|
"./orchestrator": {
|
|
36
36
|
"import": "./orchestrator.js"
|
|
37
|
+
},
|
|
38
|
+
"./workflow": {
|
|
39
|
+
"import": "./workflow.js"
|
|
40
|
+
},
|
|
41
|
+
"./tools": {
|
|
42
|
+
"import": "./tools.js"
|
|
43
|
+
},
|
|
44
|
+
"./server": {
|
|
45
|
+
"import": "./server.js"
|
|
37
46
|
}
|
|
38
47
|
},
|
|
39
48
|
"scripts": {
|
|
40
49
|
"start": "node index.js",
|
|
50
|
+
"serve": "node cli.js serve",
|
|
41
51
|
"test": "node --test",
|
|
42
52
|
"stats": "node scripts/generate-stats.js --all",
|
|
43
53
|
"stats:badge": "node scripts/generate-stats.js --badge",
|
|
@@ -46,8 +56,7 @@
|
|
|
46
56
|
"postversion": "git push && git push --tags"
|
|
47
57
|
},
|
|
48
58
|
"publishConfig": {
|
|
49
|
-
"access": "public"
|
|
50
|
-
"provenance": true
|
|
59
|
+
"access": "public"
|
|
51
60
|
},
|
|
52
61
|
"funding": {
|
|
53
62
|
"type": "github",
|
|
@@ -120,14 +129,26 @@
|
|
|
120
129
|
"node": ">=18.0.0"
|
|
121
130
|
},
|
|
122
131
|
"dependencies": {
|
|
123
|
-
"@modelcontextprotocol/sdk": "^1.26.0"
|
|
132
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
133
|
+
"express": "^4.21.0"
|
|
124
134
|
},
|
|
125
135
|
"optionalDependencies": {
|
|
126
|
-
"
|
|
136
|
+
"0n-spec": "^1.1.0"
|
|
137
|
+
},
|
|
138
|
+
"peerDependencies": {
|
|
139
|
+
"@anthropic-ai/sdk": ">=0.30.0"
|
|
140
|
+
},
|
|
141
|
+
"peerDependenciesMeta": {
|
|
142
|
+
"@anthropic-ai/sdk": {
|
|
143
|
+
"optional": true
|
|
144
|
+
}
|
|
127
145
|
},
|
|
128
146
|
"files": [
|
|
129
147
|
"index.js",
|
|
130
148
|
"cli.js",
|
|
149
|
+
"tools.js",
|
|
150
|
+
"workflow.js",
|
|
151
|
+
"server.js",
|
|
131
152
|
"catalog.js",
|
|
132
153
|
"connections.js",
|
|
133
154
|
"orchestrator.js",
|
|
@@ -142,11 +163,13 @@
|
|
|
142
163
|
],
|
|
143
164
|
"0nmcp-stats": {
|
|
144
165
|
"tools": 290,
|
|
166
|
+
"crmTools": 245,
|
|
167
|
+
"totalTools": 535,
|
|
145
168
|
"services": 26,
|
|
146
169
|
"actions": 65,
|
|
147
170
|
"triggers": 93,
|
|
148
|
-
"totalCapabilities":
|
|
171
|
+
"totalCapabilities": 693,
|
|
149
172
|
"categories": 13,
|
|
150
|
-
"lastUpdated": "2026-02-
|
|
173
|
+
"lastUpdated": "2026-02-15T00:13:31.784Z"
|
|
151
174
|
}
|
|
152
175
|
}
|