@majkapp/plugin-kit 3.2.1 → 3.3.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.
@@ -0,0 +1,490 @@
1
+ # MCP Execution API
2
+
3
+ The MCP Execution API provides context-aware operations for interacting with MCP servers from your plugin. You can operate as an admin (system-level secrets) or as a specific teammate (user-scoped secrets).
4
+
5
+ ## Quick Start
6
+
7
+ ```typescript
8
+ import { definePlugin } from '@majkapp/plugin-kit';
9
+
10
+ export default definePlugin('my-plugin')
11
+ .withApi(async (ctx) => {
12
+ const { majk } = ctx;
13
+
14
+ // Single server operations
15
+ const server = await majk.mcpServers.get('server-id');
16
+
17
+ // Admin context - uses system secrets
18
+ const adminTools = await server.asAdmin().discoverTools();
19
+ const result = await server.asAdmin().executeTool('tool-name', { param: 'value' });
20
+
21
+ // Teammate context - uses teammate-specific secrets
22
+ const teammateTools = await server.asTeammate('teammate-id').discoverTools();
23
+ const result2 = await server.asTeammate('teammate-id').executeTool('tool-name', {});
24
+
25
+ // Everywhere - operate across all servers
26
+ const allTools = await majk.mcpServers.everywhere().asAdmin().discoverTools();
27
+ const anyResult = await majk.mcpServers.everywhere()
28
+ .asTeammate('tm-id')
29
+ .executeTool('any-tool', {});
30
+ });
31
+ ```
32
+
33
+ ## API Reference
34
+
35
+ ### MCPServerHandle
36
+
37
+ Extended with context-aware methods:
38
+
39
+ #### `.asAdmin(): MCPServerScopedHandle`
40
+
41
+ Creates an admin-scoped handle that uses system-level secrets.
42
+
43
+ ```typescript
44
+ const server = await ctx.majk.mcpServers.get('openai-server');
45
+ const adminScope = server.asAdmin();
46
+
47
+ // All operations use system secrets
48
+ const tools = await adminScope.discoverTools();
49
+ const result = await adminScope.executeTool('gpt-4-call', {
50
+ prompt: 'Hello world'
51
+ });
52
+ ```
53
+
54
+ #### `.asTeammate(teammateId: string): MCPServerScopedHandle`
55
+
56
+ Creates a teammate-scoped handle that uses teammate-specific secrets.
57
+
58
+ ```typescript
59
+ const server = await ctx.majk.mcpServers.get('openai-server');
60
+ const teammateScope = server.asTeammate('teammate-123');
61
+
62
+ // All operations use teammate's secrets
63
+ const tools = await teammateScope.discoverTools();
64
+ const result = await teammateScope.executeTool('gpt-4-call', {
65
+ prompt: 'Hello from teammate'
66
+ });
67
+ ```
68
+
69
+ ### MCPServerScopedHandle
70
+
71
+ Context-aware operations on a single server:
72
+
73
+ #### `.discoverTools(): Promise<DiscoveredTool[]>`
74
+
75
+ Discovers available tools from the MCP server.
76
+
77
+ ```typescript
78
+ const tools = await server.asAdmin().discoverTools();
79
+ console.log(`Found ${tools.length} tools`);
80
+
81
+ tools.forEach(tool => {
82
+ console.log(`- ${tool.name}: ${tool.description}`);
83
+ });
84
+ ```
85
+
86
+ **Returns:**
87
+ ```typescript
88
+ interface DiscoveredTool {
89
+ id: string; // Tool identifier
90
+ name: string; // Tool name
91
+ description: string; // Tool description
92
+ inputSchema?: any; // JSON schema for inputs
93
+ serverId: string; // Server ID
94
+ serverName: string; // Server name
95
+ }
96
+ ```
97
+
98
+ #### `.executeTool(toolName: string, params: Record<string, any>): Promise<any>`
99
+
100
+ Executes a specific tool on the MCP server.
101
+
102
+ ```typescript
103
+ const result = await server.asTeammate('tm-123').executeTool('gpt-4-call', {
104
+ prompt: 'Translate to Spanish: Hello world',
105
+ temperature: 0.7
106
+ });
107
+
108
+ console.log(result.content);
109
+ ```
110
+
111
+ #### `.listResources(): Promise<any[]>`
112
+
113
+ Lists available MCP resources.
114
+
115
+ ```typescript
116
+ const resources = await server.asAdmin().listResources();
117
+ console.log('Available resources:', resources);
118
+ ```
119
+
120
+ #### `.listPrompts(): Promise<any[]>`
121
+
122
+ Lists available MCP prompts.
123
+
124
+ ```typescript
125
+ const prompts = await server.asAdmin().listPrompts();
126
+ console.log('Available prompts:', prompts);
127
+ ```
128
+
129
+ #### `.getServerInfo(): object`
130
+
131
+ Gets information about the server and context.
132
+
133
+ ```typescript
134
+ const info = server.asTeammate('tm-123').getServerInfo();
135
+ console.log(info);
136
+ // {
137
+ // id: 'server-id',
138
+ // name: 'OpenAI Server',
139
+ // type: 'local',
140
+ // context: 'teammate'
141
+ // }
142
+ ```
143
+
144
+ #### `.connect(): Promise<void>`
145
+
146
+ Manually establishes a connection (lazy by default).
147
+
148
+ ```typescript
149
+ await server.asAdmin().connect();
150
+ ```
151
+
152
+ #### `.disconnect(): Promise<void>`
153
+
154
+ Manually closes the connection.
155
+
156
+ ```typescript
157
+ await server.asAdmin().disconnect();
158
+ ```
159
+
160
+ ### MCPServerAPI
161
+
162
+ Extended with everywhere scope:
163
+
164
+ #### `.everywhere(): EverywhereScope`
165
+
166
+ Creates a scope for operating across all MCP servers.
167
+
168
+ ```typescript
169
+ const everywhere = ctx.majk.mcpServers.everywhere();
170
+
171
+ // Then scope to admin or teammate
172
+ const adminScope = everywhere.asAdmin();
173
+ const teammateScope = everywhere.asTeammate('tm-123');
174
+ ```
175
+
176
+ ### EverywhereScope
177
+
178
+ Choose execution context:
179
+
180
+ #### `.asAdmin(): EverywhereScopedHandle`
181
+
182
+ Operate as admin across all servers.
183
+
184
+ ```typescript
185
+ const scope = ctx.majk.mcpServers.everywhere().asAdmin();
186
+ ```
187
+
188
+ #### `.asTeammate(teammateId: string): EverywhereScopedHandle`
189
+
190
+ Operate as teammate across all servers.
191
+
192
+ ```typescript
193
+ const scope = ctx.majk.mcpServers.everywhere().asTeammate('tm-123');
194
+ ```
195
+
196
+ ### EverywhereScopedHandle
197
+
198
+ Aggregate operations across all servers:
199
+
200
+ #### `.discoverTools(): Promise<DiscoveredTool[]>`
201
+
202
+ Discovers tools from all MCP servers in parallel.
203
+
204
+ ```typescript
205
+ const allTools = await ctx.majk.mcpServers
206
+ .everywhere()
207
+ .asAdmin()
208
+ .discoverTools();
209
+
210
+ console.log(`Found ${allTools.length} tools across all servers`);
211
+
212
+ // Group by server
213
+ const byServer = {};
214
+ allTools.forEach(tool => {
215
+ byServer[tool.serverName] = byServer[tool.serverName] || [];
216
+ byServer[tool.serverName].push(tool);
217
+ });
218
+ ```
219
+
220
+ **Note:** Uses `Promise.allSettled` - some servers can fail without affecting others.
221
+
222
+ #### `.executeTool(toolName: string, params: Record<string, any>): Promise<any>`
223
+
224
+ Automatically finds the server that provides a tool and executes it.
225
+
226
+ ```typescript
227
+ // No need to know which server has the tool
228
+ const result = await ctx.majk.mcpServers
229
+ .everywhere()
230
+ .asTeammate('tm-123')
231
+ .executeTool('any-tool-name', { param: 'value' });
232
+ ```
233
+
234
+ **How it works:**
235
+ 1. Queries the tool repository to find which server provides the tool
236
+ 2. Creates a connection to that server with the appropriate context
237
+ 3. Executes the tool
238
+ 4. Returns the result
239
+
240
+ #### `.listKnownTools(): Promise<any[]>`
241
+
242
+ Lists all tools from the tool repository (not live discovery).
243
+
244
+ ```typescript
245
+ const knownTools = await ctx.majk.mcpServers
246
+ .everywhere()
247
+ .asAdmin()
248
+ .listKnownTools();
249
+ ```
250
+
251
+ #### `.getContextInfo(): object`
252
+
253
+ Gets information about the execution context.
254
+
255
+ ```typescript
256
+ const info = ctx.majk.mcpServers
257
+ .everywhere()
258
+ .asTeammate('tm-123')
259
+ .getContextInfo();
260
+
261
+ console.log(info);
262
+ // {
263
+ // type: 'teammate',
264
+ // id: 'tm-123',
265
+ // metadata: { context: 'teammate', teammateId: 'tm-123', scope: 'user' }
266
+ // }
267
+ ```
268
+
269
+ ## Secret Management
270
+
271
+ The execution system supports transparent secret resolution using `${secret:name}` syntax in MCP server configurations.
272
+
273
+ ### Creating Servers with Secrets
274
+
275
+ ```typescript
276
+ await ctx.majk.mcpServers.create({
277
+ name: 'OpenAI Server',
278
+ type: 'local',
279
+ connectionConfig: {
280
+ command: 'node',
281
+ args: ['mcp-server.js'],
282
+ env: {
283
+ // Each teammate will use their own API key
284
+ OPENAI_API_KEY: '${secret:openai_api_key}',
285
+
286
+ // Explicit global scope
287
+ GLOBAL_TOKEN: '${secret:global/api_token}',
288
+
289
+ // Environment variable
290
+ PATH: '${env:PATH}'
291
+ }
292
+ }
293
+ });
294
+ ```
295
+
296
+ ### Secret Scopes
297
+
298
+ - `${secret:name}` - Uses context scope (global for admin, teammate for teammate)
299
+ - `${secret:global/name}` - Explicit global scope
300
+ - `${secret:teammate/name}` - Explicit teammate scope
301
+ - `${secret:project/name}` - Explicit project scope
302
+ - `${env:VAR}` - Environment variable
303
+
304
+ ### How It Works
305
+
306
+ 1. When you call `.asAdmin()` or `.asTeammate(id)`, a context is created
307
+ 2. The context determines which secrets to resolve
308
+ 3. On connection, `${secret:*}` references are replaced with actual values
309
+ 4. Each context gets its own connection with its own resolved secrets
310
+ 5. Admin contexts use system/global secrets
311
+ 6. Teammate contexts use teammate-specific secrets
312
+
313
+ ## Event Monitoring
314
+
315
+ All MCP operations emit events that you can subscribe to:
316
+
317
+ ```typescript
318
+ // Subscribe to MCP server events
319
+ ctx.majk.eventBus.mcpServers().onUpdated(async (server) => {
320
+ // Check for tool discovery events
321
+ if (server.metadata?.type === 'tool_discovery_completed') {
322
+ console.log(`Discovered ${server.metadata.toolCount} tools`);
323
+ }
324
+
325
+ // Check for tool execution events
326
+ if (server.metadata?.type === 'tool_execution_completed') {
327
+ console.log(`Executed ${server.metadata.toolName} in ${server.metadata.duration}ms`);
328
+ }
329
+ });
330
+ ```
331
+
332
+ ### Event Types
333
+
334
+ Discovery events:
335
+ - `tool_discovery_started`
336
+ - `tool_discovery_completed`
337
+ - `tool_discovery_failed`
338
+
339
+ Execution events:
340
+ - `tool_execution_started`
341
+ - `tool_execution_completed`
342
+ - `tool_execution_failed`
343
+
344
+ Connection events:
345
+ - `connection_established`
346
+ - `connection_closed`
347
+ - `secrets_resolved`
348
+
349
+ Everywhere events:
350
+ - `everywhere_discovery_started`
351
+ - `everywhere_discovery_completed`
352
+ - `everywhere_discovery_failed`
353
+ - `everywhere_execution_started`
354
+ - `everywhere_execution_completed`
355
+ - `everywhere_execution_failed`
356
+
357
+ ## Common Patterns
358
+
359
+ ### Tool Discovery Dashboard
360
+
361
+ ```typescript
362
+ export default definePlugin('tool-dashboard')
363
+ .withApi(async (ctx) => {
364
+ // Discover tools from all servers
365
+ const allTools = await ctx.majk.mcpServers
366
+ .everywhere()
367
+ .asAdmin()
368
+ .discoverTools();
369
+
370
+ // Group by server
371
+ const byServer = {};
372
+ allTools.forEach(tool => {
373
+ if (!byServer[tool.serverName]) {
374
+ byServer[tool.serverName] = [];
375
+ }
376
+ byServer[tool.serverName].push(tool);
377
+ });
378
+
379
+ return {
380
+ toolsByServer: byServer,
381
+ totalTools: allTools.length,
382
+ totalServers: Object.keys(byServer).length
383
+ };
384
+ });
385
+ ```
386
+
387
+ ### Teammate-Specific Tool Execution
388
+
389
+ ```typescript
390
+ export default definePlugin('teammate-tools')
391
+ .withApi(async (ctx) => ({
392
+ executeForTeammate: async (teammateId: string, toolName: string, params: any) => {
393
+ try {
394
+ const result = await ctx.majk.mcpServers
395
+ .everywhere()
396
+ .asTeammate(teammateId)
397
+ .executeTool(toolName, params);
398
+
399
+ return { success: true, result };
400
+ } catch (error) {
401
+ return { success: false, error: error.message };
402
+ }
403
+ }
404
+ }));
405
+ ```
406
+
407
+ ### Admin Tool Management
408
+
409
+ ```typescript
410
+ export default definePlugin('admin-tools')
411
+ .withApi(async (ctx) => {
412
+ const servers = await ctx.majk.mcpServers.list();
413
+
414
+ // Discover tools from each server as admin
415
+ const discoveries = await Promise.all(
416
+ servers.map(async server => {
417
+ try {
418
+ const tools = await server.asAdmin().discoverTools();
419
+ return { serverId: server.id, serverName: server.name, tools };
420
+ } catch (error) {
421
+ return { serverId: server.id, serverName: server.name, error: error.message };
422
+ }
423
+ })
424
+ );
425
+
426
+ return { discoveries };
427
+ });
428
+ ```
429
+
430
+ ### Connection Pool Monitoring
431
+
432
+ ```typescript
433
+ // Monitor connection lifecycle
434
+ ctx.majk.eventBus.mcpServers().subscribe(async (event) => {
435
+ if (event.metadata?.type === 'connection_established') {
436
+ console.log(`Connection established: ${event.metadata.poolKey}`);
437
+ }
438
+
439
+ if (event.metadata?.type === 'connection_closed') {
440
+ console.log(`Connection closed: ${event.metadata.poolKey}`);
441
+ }
442
+ });
443
+ ```
444
+
445
+ ## Best Practices
446
+
447
+ 1. **Use appropriate context**: Admin for system operations, teammate for user actions
448
+ 2. **Handle errors gracefully**: Tool execution can fail, always wrap in try/catch
449
+ 3. **Monitor events**: Subscribe to events for observability
450
+ 4. **Leverage everywhere**: Use `.everywhere()` when you don't know which server has a tool
451
+ 5. **Clean up connections**: Connections auto-cleanup after 5 min idle, but you can manually disconnect
452
+ 6. **Secure secrets**: Never log or expose resolved secrets
453
+
454
+ ## TypeScript Support
455
+
456
+ Full TypeScript support with type inference:
457
+
458
+ ```typescript
459
+ import type {
460
+ MCPServerHandle,
461
+ MCPServerScopedHandle,
462
+ DiscoveredTool,
463
+ EverywhereScope,
464
+ EverywhereScopedHandle
465
+ } from '@majkapp/plugin-kit';
466
+
467
+ // Type-safe operations
468
+ const server: MCPServerHandle = await ctx.majk.mcpServers.get('id');
469
+ const scope: MCPServerScopedHandle = server.asAdmin();
470
+ const tools: DiscoveredTool[] = await scope.discoverTools();
471
+ ```
472
+
473
+ ## Performance Notes
474
+
475
+ - **Connection pooling**: Connections are reused within the same context
476
+ - **Parallel discovery**: `everywhere().discoverTools()` runs in parallel across servers
477
+ - **Lazy connections**: Connections are created on first use, not on `.asAdmin()/.asTeammate()`
478
+ - **Auto cleanup**: Idle connections are cleaned up after 5 minutes
479
+
480
+ ## Migration from Legacy API
481
+
482
+ If you were using direct MCP operations:
483
+
484
+ ```typescript
485
+ // OLD
486
+ const tools = await ctx.majk.mcpServers.get('id').then(s => s.getTools());
487
+
488
+ // NEW - with context awareness
489
+ const tools = await ctx.majk.mcpServers.get('id').then(s => s.asAdmin().discoverTools());
490
+ ```
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@majkapp/plugin-kit",
3
- "version": "3.2.1",
3
+ "version": "3.3.1",
4
4
  "description": "Pure plugin definition library for MAJK - outputs plugin definitions, not HTTP servers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": {
8
- "plugin-kit": "./dist/generator/cli.js"
8
+ "plugin-kit": "./dist/generator/cli.js",
9
+ "majk-plugin-kit": "./dist/generator/cli.js"
9
10
  },
10
11
  "repository": {
11
12
  "type": "git",
@@ -18,12 +19,25 @@
18
19
  },
19
20
  "files": [
20
21
  "dist",
22
+ "bin",
23
+ "docs",
21
24
  "README.md"
22
25
  ],
23
26
  "scripts": {
24
27
  "build": "tsc && cp src/mcp-dom-agent.js dist/",
25
28
  "watch": "tsc --watch",
26
- "clean": "rm -rf dist"
29
+ "clean": "rm -rf dist",
30
+ "promptable": "node ./bin/promptable-cli.js --llm",
31
+ "promptable:functions": "node ./bin/promptable-cli.js --functions",
32
+ "promptable:screens": "node ./bin/promptable-cli.js --screens",
33
+ "promptable:hooks": "node ./bin/promptable-cli.js --hooks",
34
+ "promptable:context": "node ./bin/promptable-cli.js --context",
35
+ "promptable:services": "node ./bin/promptable-cli.js --services",
36
+ "promptable:lifecycle": "node ./bin/promptable-cli.js --lifecycle",
37
+ "promptable:testing": "node ./bin/promptable-cli.js --testing",
38
+ "promptable:config": "node ./bin/promptable-cli.js --config",
39
+ "promptable:api": "node ./bin/promptable-cli.js --api",
40
+ "promptable:full": "node ./bin/promptable-cli.js --full"
27
41
  },
28
42
  "keywords": [
29
43
  "majk",
@@ -33,6 +47,7 @@
33
47
  ],
34
48
  "author": "Majk Contributors",
35
49
  "dependencies": {
50
+ "@juleswhite/promptable": "^1.0.2",
36
51
  "commander": "^11.1.0",
37
52
  "html2canvas": "^1.4.1"
38
53
  },