@agent-deck/backend 1.2.10 → 1.3.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.
@@ -10,9 +10,10 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
10
10
  const shared_1 = require("@agent-deck/shared");
11
11
  const express_1 = __importDefault(require("express"));
12
12
  const node_crypto_1 = require("node:crypto");
13
- const zod_1 = require("zod");
14
13
  const version_1 = require("./lib/version");
15
14
  const mcp_session_binding_1 = require("./mcp-session-binding");
15
+ const register_1 = require("./mcp-tools/register");
16
+ const profile_1 = require("./mcp-tools/profile");
16
17
  const agentClientHeaders = {
17
18
  [shared_1.AGENT_DECK_CLIENT_HEADER]: shared_1.AGENT_DECK_AGENT_CLIENT,
18
19
  Accept: 'application/json',
@@ -21,6 +22,7 @@ class AgentDeckMCPServer {
21
22
  port;
22
23
  app;
23
24
  backendUrl;
25
+ toolProfile;
24
26
  sessions = new Map();
25
27
  /** Set only while registerTools/registerResources run for a new session server. */
26
28
  mcpServerForRegistration;
@@ -36,9 +38,10 @@ class AgentDeckMCPServer {
36
38
  }
37
39
  return this.mcpServerForRegistration;
38
40
  }
39
- constructor(port = 3001, backendUrl = 'http://localhost:8000') {
41
+ constructor(port = 3001, backendUrl = 'http://localhost:8000', toolProfile) {
40
42
  this.port = port;
41
43
  this.backendUrl = backendUrl;
44
+ this.toolProfile = toolProfile ?? (0, profile_1.resolveMcpToolProfile)();
42
45
  this.app = (0, express_1.default)();
43
46
  this.app.use(express_1.default.json());
44
47
  this.setupRoutes();
@@ -206,647 +209,21 @@ class AgentDeckMCPServer {
206
209
  this.server.registerTool(name, config, handler);
207
210
  }
208
211
  setupTools() {
209
- this.registerTool("bind_workspace", {
210
- title: "Bind Workspace",
211
- description: "Bind this MCP session to a workspace root and deck. Use get_decks to list deck ids.",
212
- inputSchema: {
213
- workspaceRoot: zod_1.z.string(),
214
- deckId: zod_1.z.string().uuid(),
215
- },
216
- }, async ({ workspaceRoot, deckId }) => {
217
- try {
218
- const sessionId = this.getSessionId();
219
- this.sessionBinding.setWorkspace(sessionId, workspaceRoot);
220
- const deck = await this.fetchDeck(deckId);
221
- this.sessionBinding.setDeckId(sessionId, deckId);
222
- await this.registerLiveDisplay(sessionId);
223
- const payload = await this.buildBindingPayload(sessionId);
224
- return {
225
- content: [{
226
- type: "text",
227
- text: JSON.stringify({
228
- ...payload,
229
- deck_name: deck.name,
230
- message: 'Session bound to deck.',
231
- }, null, 2),
232
- }],
233
- };
234
- }
235
- catch (error) {
236
- return this.toolError(error);
237
- }
238
- });
239
- this.registerTool("switch_bound_deck", {
240
- title: "Switch Bound Deck",
241
- description: "Switch the deck for this MCP session only. Use when multiple agent sessions share the same workspace path.",
242
- inputSchema: { deckId: zod_1.z.string().uuid() },
243
- }, async ({ deckId }) => {
244
- try {
245
- const sessionId = this.getSessionId();
246
- const deck = await this.fetchDeck(deckId);
247
- this.sessionBinding.setDeckId(sessionId, deckId);
248
- await this.registerLiveDisplay(sessionId);
249
- const payload = await this.buildBindingPayload(sessionId);
250
- return {
251
- content: [{
252
- type: "text",
253
- text: JSON.stringify({
254
- ...payload,
255
- deck_name: deck.name,
256
- message: 'Session deck switched. Other sessions are unchanged.',
257
- }, null, 2),
258
- }],
259
- };
260
- }
261
- catch (error) {
262
- return this.toolError(error);
263
- }
264
- });
265
- this.registerTool("get_session_binding", {
266
- title: "Get Session Binding",
267
- description: "Show workspace and effective deck for this MCP session (session override or env default).",
268
- inputSchema: {},
269
- }, async () => {
270
- try {
271
- const sessionId = this.getSessionId();
272
- const snapshot = this.sessionBinding.getBinding(sessionId);
273
- const deck = await this.callBackendAPI('/api/scope/deck');
274
- const badge = this.badgeBySession.get(sessionId);
275
- const cardCounts = deck ? (0, shared_1.countDeckCards)(deck) : { mcp: 0, credentials: 0, playbooks: 0 };
276
- const displaySummary = (0, shared_1.formatDisplayLine)(deck?.name ?? null, cardCounts, { badge });
277
- return {
278
- content: [{
279
- type: "text",
280
- text: JSON.stringify({
281
- workspaceRoot: snapshot.workspaceRoot,
282
- session_deck_id: snapshot.deckId,
283
- session_deck_source: snapshot.deckSource,
284
- effective_deck_id: deck?.id,
285
- effective_deck_name: deck?.name,
286
- effective_deck_source: (0, mcp_session_binding_1.resolveDeckBindingSource)(snapshot),
287
- badge,
288
- display_summary: displaySummary,
289
- }, null, 2),
290
- }],
291
- };
292
- }
293
- catch (error) {
294
- return this.toolError(error);
295
- }
296
- });
297
- // Get all decks (metadata only; credentials stripped unless bound)
298
- this.registerTool("get_decks", {
299
- title: "Get Decks",
300
- description: "Get all available decks from Agent Deck",
301
- inputSchema: {}
302
- }, async () => {
303
- try {
304
- const decks = await this.callBackendAPI('/api/decks');
305
- return {
306
- content: [{ type: "text", text: JSON.stringify(decks, null, 2) }]
307
- };
308
- }
309
- catch (error) {
310
- return {
311
- content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }]
312
- };
313
- }
314
- });
315
- this.registerTool("get_bound_deck", {
316
- title: "Get Bound Deck",
317
- description: "Get the deck bound to this session (session deckId or env AGENT_DECK_DECK_ID)",
318
- inputSchema: {},
319
- }, async () => {
320
- try {
321
- const deck = await this.callBackendAPI('/api/scope/deck');
322
- return {
323
- content: [{ type: "text", text: JSON.stringify(deck, null, 2) }],
324
- };
325
- }
326
- catch (error) {
327
- return {
328
- content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }],
329
- };
330
- }
331
- });
332
- // Deprecated alias
333
- this.registerTool("get_active_deck", {
334
- title: "Get Active Deck (deprecated)",
335
- description: "Deprecated — use get_bound_deck. Returns the workspace-bound deck.",
336
- inputSchema: {},
337
- }, async () => {
338
- try {
339
- const deck = await this.callBackendAPI('/api/scope/deck');
340
- return {
341
- content: [{ type: "text", text: JSON.stringify(deck, null, 2) }],
342
- };
343
- }
344
- catch (error) {
345
- return {
346
- content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }],
347
- };
348
- }
349
- });
350
- this.registerTool("list_bound_deck_services", {
351
- title: "List Bound Deck Services",
352
- description: "List MCP services on the workspace-bound deck",
353
- inputSchema: {},
354
- }, async () => {
355
- try {
356
- const deck = await this.callBackendAPI('/api/scope/deck');
357
- const services = deck?.services ?? [];
358
- return { content: [{ type: "text", text: JSON.stringify(services, null, 2) }] };
359
- }
360
- catch (error) {
361
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
362
- }
363
- });
364
- this.registerTool("list_active_deck_services", {
365
- title: "List Active Deck Services (deprecated)",
366
- description: "Deprecated — use list_bound_deck_services",
367
- inputSchema: {},
368
- }, async () => {
369
- try {
370
- const deck = await this.callBackendAPI('/api/scope/deck');
371
- const services = deck?.services ?? [];
372
- return { content: [{ type: "text", text: JSON.stringify(services, null, 2) }] };
373
- }
374
- catch (error) {
375
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
376
- }
377
- });
378
- this.registerTool("list_bound_deck_credentials", {
379
- title: "List Bound Deck Credentials",
380
- description: "List API key metadata on the workspace-bound deck",
381
- inputSchema: {},
382
- }, async () => {
383
- try {
384
- const credentials = await this.callBackendAPI('/api/credentials');
385
- return { content: [{ type: "text", text: JSON.stringify(credentials, null, 2) }] };
386
- }
387
- catch (error) {
388
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
389
- }
390
- });
391
- this.registerTool("list_active_deck_credentials", {
392
- title: "List Active Deck Credentials (deprecated)",
393
- description: "Deprecated — use list_bound_deck_credentials",
394
- inputSchema: {},
395
- }, async () => {
396
- try {
397
- const credentials = await this.callBackendAPI('/api/credentials');
398
- return { content: [{ type: "text", text: JSON.stringify(credentials, null, 2) }] };
399
- }
400
- catch (error) {
401
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
402
- }
403
- });
404
- this.registerTool("list_playbooks", {
405
- title: "List Playbooks",
406
- description: "List playbook cards on the bound deck (id, title, triggers)",
407
- inputSchema: {},
408
- }, async () => {
409
- try {
410
- const playbooks = await this.callBackendAPI('/api/playbooks/summaries');
411
- return { content: [{ type: "text", text: JSON.stringify(playbooks, null, 2) }] };
412
- }
413
- catch (error) {
414
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
415
- }
416
- });
417
- this.registerTool("get_playbook", {
418
- title: "Get Playbook",
419
- description: "Get full markdown body, metadata, and dependencies for a playbook card by id",
420
- inputSchema: { playbook_id: zod_1.z.string() },
421
- }, async ({ playbook_id }) => {
422
- try {
423
- const playbook = await this.callBackendAPI(`/api/playbooks/${encodeURIComponent(playbook_id)}`);
424
- return { content: [{ type: "text", text: JSON.stringify(playbook, null, 2) }] };
425
- }
426
- catch (error) {
427
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
428
- }
429
- });
430
- this.registerTool("register_playbook", {
431
- title: "Register Playbook",
432
- description: "Create a playbook card, auto-detect API key and MCP dependencies from the content, and add it to the bound deck by default",
433
- inputSchema: {
434
- title: zod_1.z.string(),
435
- body: zod_1.z.string(),
436
- triggers: zod_1.z.array(zod_1.z.string()).optional(),
437
- playbook_id: zod_1.z.string().optional(),
438
- exec: zod_1.z.string().optional(),
439
- skill: zod_1.z.string().optional(),
440
- depends_on_credential_ids: zod_1.z.array(zod_1.z.string()).optional(),
441
- depends_on_service_ids: zod_1.z.array(zod_1.z.string()).optional(),
442
- add_to_bound_deck: zod_1.z.boolean().optional(),
443
- auto_detect_dependencies: zod_1.z.boolean().optional(),
444
- },
445
- }, async (args) => {
446
- try {
447
- const playbook = await this.callBackendAPI("/api/playbooks", {
448
- method: "POST",
449
- headers: { "Content-Type": "application/json" },
450
- body: JSON.stringify({
451
- title: args.title,
452
- body: args.body,
453
- triggers: args.triggers,
454
- id: args.playbook_id,
455
- exec: args.exec,
456
- skill: args.skill,
457
- dependsOnCredentialIds: args.depends_on_credential_ids,
458
- dependsOnServiceIds: args.depends_on_service_ids,
459
- addToBoundDeck: args.add_to_bound_deck,
460
- autoDetectDependencies: args.auto_detect_dependencies,
461
- }),
462
- });
463
- return { content: [{ type: "text", text: JSON.stringify(playbook, null, 2) }] };
464
- }
465
- catch (error) {
466
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
467
- }
468
- });
469
- this.registerTool("update_playbook", {
470
- title: "Update Playbook",
471
- description: "Update a playbook on the bound deck. Dependencies are re-detected from the updated content by default.",
472
- inputSchema: {
473
- playbook_id: zod_1.z.string(),
474
- title: zod_1.z.string().optional(),
475
- body: zod_1.z.string().optional(),
476
- triggers: zod_1.z.array(zod_1.z.string()).optional(),
477
- exec: zod_1.z.string().optional(),
478
- skill: zod_1.z.string().optional(),
479
- depends_on_credential_ids: zod_1.z.array(zod_1.z.string()).optional(),
480
- depends_on_service_ids: zod_1.z.array(zod_1.z.string()).optional(),
481
- auto_detect_dependencies: zod_1.z.boolean().optional(),
482
- },
483
- }, async ({ playbook_id, ...args }) => {
484
- try {
485
- const playbook = await this.callBackendAPI(`/api/playbooks/${encodeURIComponent(playbook_id)}`, {
486
- method: "PUT",
487
- headers: { "Content-Type": "application/json" },
488
- body: JSON.stringify({
489
- title: args.title,
490
- body: args.body,
491
- triggers: args.triggers,
492
- exec: args.exec,
493
- skill: args.skill,
494
- dependsOnCredentialIds: args.depends_on_credential_ids,
495
- dependsOnServiceIds: args.depends_on_service_ids,
496
- autoDetectDependencies: args.auto_detect_dependencies,
497
- }),
498
- });
499
- return { content: [{ type: "text", text: JSON.stringify(playbook, null, 2) }] };
500
- }
501
- catch (error) {
502
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
503
- }
504
- });
505
- this.registerTool("list_collection_services", {
506
- title: "List Collection Services",
507
- description: "List all registered MCP services in the collection (metadata only)",
508
- inputSchema: {},
509
- }, async () => {
510
- try {
511
- const services = await this.callBackendAPI('/api/services');
512
- return this.toolResult(services);
513
- }
514
- catch (error) {
515
- return this.toolError(error);
516
- }
517
- });
518
- this.registerTool("register_service", {
519
- title: "Register Service",
520
- description: "Register an MCP service in the collection. Optionally add it to the bound deck. OAuth setup still requires the dashboard browser flow.",
521
- inputSchema: {
522
- name: zod_1.z.string(),
523
- type: zod_1.z.enum(['mcp', 'a2a', 'local-mcp']),
524
- url: zod_1.z.string(),
525
- description: zod_1.z.string().optional(),
526
- cardColor: zod_1.z.string().optional(),
527
- credentialId: zod_1.z.string().optional(),
528
- headers: zod_1.z.record(zod_1.z.string()).optional(),
529
- localCommand: zod_1.z.string().optional(),
530
- localArgs: zod_1.z.array(zod_1.z.string()).optional(),
531
- localWorkingDir: zod_1.z.string().optional(),
532
- localEnv: zod_1.z.record(zod_1.z.string()).optional(),
533
- add_to_bound_deck: zod_1.z.boolean().optional(),
534
- position: zod_1.z.number().optional(),
535
- },
536
- }, async (args) => {
537
- try {
538
- const { add_to_bound_deck, position, ...serviceInput } = args;
539
- const service = await this.callBackendAPI('/api/services', {
540
- method: 'POST',
541
- headers: { 'Content-Type': 'application/json' },
542
- body: JSON.stringify(serviceInput),
543
- });
544
- if (add_to_bound_deck !== false) {
545
- const deckId = await this.getBoundDeckId();
546
- await this.callBackendAPI(`/api/decks/${deckId}/services`, {
547
- method: 'POST',
548
- headers: { 'Content-Type': 'application/json' },
549
- body: JSON.stringify({ serviceId: service.id, position }),
550
- });
551
- }
552
- return this.toolResult(service);
553
- }
554
- catch (error) {
555
- return this.toolError(error);
556
- }
557
- });
558
- this.registerTool("update_service", {
559
- title: "Update Service",
560
- description: "Update MCP service metadata in the collection (not OAuth tokens — use dashboard for OAuth)",
561
- inputSchema: {
562
- service_id: zod_1.z.string(),
563
- name: zod_1.z.string().optional(),
564
- type: zod_1.z.enum(['mcp', 'a2a', 'local-mcp']).optional(),
565
- url: zod_1.z.string().optional(),
566
- description: zod_1.z.string().optional(),
567
- cardColor: zod_1.z.string().optional(),
568
- credentialId: zod_1.z.string().optional(),
569
- headers: zod_1.z.record(zod_1.z.string()).optional(),
570
- localCommand: zod_1.z.string().optional(),
571
- localArgs: zod_1.z.array(zod_1.z.string()).optional(),
572
- localWorkingDir: zod_1.z.string().optional(),
573
- localEnv: zod_1.z.record(zod_1.z.string()).optional(),
574
- },
575
- }, async ({ service_id, ...updates }) => {
576
- try {
577
- const service = await this.callBackendAPI(`/api/services/${service_id}`, {
578
- method: 'PUT',
579
- headers: { 'Content-Type': 'application/json' },
580
- body: JSON.stringify(updates),
581
- });
582
- return this.toolResult(service);
583
- }
584
- catch (error) {
585
- return this.toolError(error);
586
- }
587
- });
588
- this.registerTool("delete_service", {
589
- title: "Delete Service",
590
- description: "Remove an MCP service from the collection entirely",
591
- inputSchema: { service_id: zod_1.z.string() },
592
- }, async ({ service_id }) => {
593
- try {
594
- await this.callBackendAPI(`/api/services/${service_id}`, { method: 'DELETE' });
595
- return this.toolResult({ success: true, service_id });
596
- }
597
- catch (error) {
598
- return this.toolError(error);
599
- }
600
- });
601
- this.registerTool("add_service_to_bound_deck", {
602
- title: "Add Service To Bound Deck",
603
- description: "Link an existing MCP service from the collection onto the bound deck",
604
- inputSchema: {
605
- service_id: zod_1.z.string(),
606
- position: zod_1.z.number().optional(),
607
- },
608
- }, async ({ service_id, position }) => {
609
- try {
610
- const deckId = await this.getBoundDeckId();
611
- await this.callBackendAPI(`/api/decks/${deckId}/services`, {
612
- method: 'POST',
613
- headers: { 'Content-Type': 'application/json' },
614
- body: JSON.stringify({ serviceId: service_id, position }),
615
- });
616
- return this.toolResult({ success: true, deck_id: deckId, service_id });
617
- }
618
- catch (error) {
619
- return this.toolError(error);
620
- }
621
- });
622
- this.registerTool("remove_service_from_bound_deck", {
623
- title: "Remove Service From Bound Deck",
624
- description: "Unlink an MCP service from the bound deck (service stays in the collection)",
625
- inputSchema: { service_id: zod_1.z.string() },
626
- }, async ({ service_id }) => {
627
- try {
628
- const deckId = await this.getBoundDeckId();
629
- await this.callBackendAPI(`/api/decks/${deckId}/services`, {
630
- method: 'DELETE',
631
- headers: { 'Content-Type': 'application/json' },
632
- body: JSON.stringify({ serviceId: service_id }),
633
- });
634
- return this.toolResult({ success: true, deck_id: deckId, service_id });
635
- }
636
- catch (error) {
637
- return this.toolError(error);
638
- }
639
- });
640
- this.registerTool("update_service_tool_settings", {
641
- title: "Update Service Tool Settings",
642
- description: "Enable or disable individual tools for an MCP service on the bound deck",
643
- inputSchema: {
644
- service_id: zod_1.z.string(),
645
- disabled_tools: zod_1.z.array(zod_1.z.string()),
646
- },
647
- }, async ({ service_id, disabled_tools }) => {
648
- try {
649
- const service = await this.callBackendAPI(`/api/services/${service_id}/tool-settings`, {
650
- method: 'PUT',
651
- headers: { 'Content-Type': 'application/json' },
652
- body: JSON.stringify({ disabledTools: disabled_tools }),
653
- });
654
- return this.toolResult(service);
655
- }
656
- catch (error) {
657
- return this.toolError(error);
658
- }
659
- });
660
- this.registerTool("list_collection_credentials", {
661
- title: "List Collection Credentials",
662
- description: "List all API key metadata in the collection (no secret values). Use credential ids to link keys to the bound deck after the user stores the secret in the dashboard.",
663
- inputSchema: {},
664
- }, async () => {
665
- try {
666
- const credentials = await this.callBackendAPI('/api/credentials/collection');
667
- return this.toolResult(credentials);
668
- }
669
- catch (error) {
670
- return this.toolError(error);
671
- }
672
- });
673
- this.registerTool("add_credential_to_bound_deck", {
674
- title: "Add Credential To Bound Deck",
675
- description: "Link an existing API key (by credential id) to the bound deck. The secret must already be stored via the dashboard or CLI.",
676
- inputSchema: {
677
- credential_id: zod_1.z.string(),
678
- position: zod_1.z.number().optional(),
679
- },
680
- }, async ({ credential_id, position }) => {
681
- try {
682
- const deckId = await this.getBoundDeckId();
683
- await this.callBackendAPI(`/api/decks/${deckId}/credentials`, {
684
- method: 'POST',
685
- headers: { 'Content-Type': 'application/json' },
686
- body: JSON.stringify({ credentialId: credential_id, position }),
687
- });
688
- return this.toolResult({ success: true, deck_id: deckId, credential_id });
689
- }
690
- catch (error) {
691
- return this.toolError(error);
692
- }
693
- });
694
- this.registerTool("remove_credential_from_bound_deck", {
695
- title: "Remove Credential From Bound Deck",
696
- description: "Unlink an API key from the bound deck (credential stays in the vault)",
697
- inputSchema: { credential_id: zod_1.z.string() },
698
- }, async ({ credential_id }) => {
699
- try {
700
- const deckId = await this.getBoundDeckId();
701
- await this.callBackendAPI(`/api/decks/${deckId}/credentials`, {
702
- method: 'DELETE',
703
- headers: { 'Content-Type': 'application/json' },
704
- body: JSON.stringify({ credentialId: credential_id }),
705
- });
706
- return this.toolResult({ success: true, deck_id: deckId, credential_id });
707
- }
708
- catch (error) {
709
- return this.toolError(error);
710
- }
711
- });
712
- this.registerTool("list_collection_playbooks", {
713
- title: "List Collection Playbooks",
714
- description: "List all playbook cards in the collection (for linking existing playbooks to the bound deck)",
715
- inputSchema: {},
716
- }, async () => {
717
- try {
718
- const playbooks = await this.callBackendAPI('/api/playbooks/collection');
719
- return this.toolResult(playbooks);
720
- }
721
- catch (error) {
722
- return this.toolError(error);
723
- }
724
- });
725
- this.registerTool("add_playbook_to_bound_deck", {
726
- title: "Add Playbook To Bound Deck",
727
- description: "Link an existing playbook card from the collection onto the bound deck",
728
- inputSchema: {
729
- playbook_id: zod_1.z.string(),
730
- position: zod_1.z.number().optional(),
731
- },
732
- }, async ({ playbook_id, position }) => {
733
- try {
734
- const deckId = await this.getBoundDeckId();
735
- await this.callBackendAPI(`/api/decks/${deckId}/playbooks`, {
736
- method: 'POST',
737
- headers: { 'Content-Type': 'application/json' },
738
- body: JSON.stringify({ playbookId: playbook_id, position }),
739
- });
740
- return this.toolResult({ success: true, deck_id: deckId, playbook_id });
741
- }
742
- catch (error) {
743
- return this.toolError(error);
744
- }
745
- });
746
- this.registerTool("remove_playbook_from_bound_deck", {
747
- title: "Remove Playbook From Bound Deck",
748
- description: "Unlink a playbook from the bound deck (playbook stays in the collection)",
749
- inputSchema: { playbook_id: zod_1.z.string() },
750
- }, async ({ playbook_id }) => {
751
- try {
752
- const deckId = await this.getBoundDeckId();
753
- await this.callBackendAPI(`/api/decks/${deckId}/playbooks`, {
754
- method: 'DELETE',
755
- headers: { 'Content-Type': 'application/json' },
756
- body: JSON.stringify({ playbookId: playbook_id }),
757
- });
758
- return this.toolResult({ success: true, deck_id: deckId, playbook_id });
759
- }
760
- catch (error) {
761
- return this.toolError(error);
762
- }
763
- });
764
- this.registerTool("delete_playbook", {
765
- title: "Delete Playbook",
766
- description: "Delete a playbook from the collection (must be on the bound deck for agent clients)",
767
- inputSchema: { playbook_id: zod_1.z.string() },
768
- }, async ({ playbook_id }) => {
769
- try {
770
- await this.callBackendAPI(`/api/playbooks/${encodeURIComponent(playbook_id)}`, {
771
- method: 'DELETE',
772
- });
773
- return this.toolResult({ success: true, playbook_id });
774
- }
775
- catch (error) {
776
- return this.toolError(error);
777
- }
778
- });
779
- this.registerTool("create_deck", {
780
- title: "Create Deck",
781
- description: "Create a new deck in Agent Deck",
782
- inputSchema: {
783
- name: zod_1.z.string(),
784
- description: zod_1.z.string().optional(),
785
- },
786
- }, async ({ name, description }) => {
787
- try {
788
- const deck = await this.callBackendAPI('/api/decks', {
789
- method: 'POST',
790
- headers: { 'Content-Type': 'application/json' },
791
- body: JSON.stringify({ name, description }),
792
- });
793
- return this.toolResult(deck);
794
- }
795
- catch (error) {
796
- return this.toolError(error);
797
- }
798
- });
799
- // Remove duplicate old tools block - list_service_tools follows
800
- this.registerTool("list_service_tools", {
801
- title: "List Service Tools",
802
- description: "List all available tools for a specific service in the active deck",
803
- inputSchema: { serviceId: zod_1.z.string() }
804
- }, async ({ serviceId }) => {
805
- try {
806
- const tools = await this.callBackendAPI(`/api/services/${serviceId}/tools`);
807
- return { content: [{ type: "text", text: JSON.stringify(tools, null, 2) }] };
808
- }
809
- catch (error) {
810
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
811
- }
812
- });
813
- // Call a tool on a service in the active deck
814
- this.registerTool("call_service_tool", {
815
- title: "Call Service Tool",
816
- description: "Call a tool on a service from the active deck",
817
- inputSchema: {
818
- serviceId: zod_1.z.string(),
819
- toolName: zod_1.z.string(),
820
- arguments: zod_1.z.union([zod_1.z.record(zod_1.z.any()), zod_1.z.string()]).optional()
821
- }
822
- }, async ({ serviceId, toolName, arguments: args = {} }) => {
823
- try {
824
- // Support both object and JSON string inputs for arguments
825
- let normalizedArgs = args;
826
- if (typeof normalizedArgs === 'string' && normalizedArgs.length > 0) {
827
- try {
828
- normalizedArgs = JSON.parse(normalizedArgs);
829
- }
830
- catch (e) {
831
- return { content: [{ type: "text", text: JSON.stringify({ error: `Invalid JSON in arguments: ${String(e)}` }, null, 2) }] };
832
- }
833
- }
834
- const res = await fetch(`${this.backendUrl}/api/services/${serviceId}/call`, {
835
- method: 'POST',
836
- headers: { ...this.getAgentHeaders(), 'Content-Type': 'application/json' },
837
- body: JSON.stringify({ toolName, arguments: normalizedArgs ?? {} })
838
- });
839
- if (!res.ok) {
840
- const text = await res.text();
841
- throw new Error(`Backend API error ${res.status}: ${text}`);
842
- }
843
- const body = await res.json();
844
- const data = (body && body.success) ? (body.data ?? body.result ?? body) : body;
845
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
846
- }
847
- catch (error) {
848
- return { content: [{ type: "text", text: JSON.stringify({ error: String(error) }, null, 2) }] };
849
- }
212
+ (0, register_1.registerMcpTools)({
213
+ registerTool: (name, config, handler) => this.registerTool(name, config, handler),
214
+ profile: this.toolProfile,
215
+ getSessionId: () => this.getSessionId(),
216
+ getAgentHeaders: () => this.getAgentHeaders(),
217
+ getBoundDeckId: () => this.getBoundDeckId(),
218
+ callBackendAPI: (endpoint, init) => this.callBackendAPI(endpoint, init),
219
+ fetchDeck: (deckId) => this.fetchDeck(deckId),
220
+ buildBindingPayload: (sessionId) => this.buildBindingPayload(sessionId),
221
+ registerLiveDisplay: (sessionId) => this.registerLiveDisplay(sessionId),
222
+ sessionBinding: this.sessionBinding,
223
+ badgeBySession: this.badgeBySession,
224
+ backendUrl: this.backendUrl,
225
+ toolResult: (data) => this.toolResult(data),
226
+ toolError: (error) => this.toolError(error),
850
227
  });
851
228
  }
852
229
  setupResources() {
@@ -1062,7 +439,8 @@ class AgentDeckMCPServer {
1062
439
  res.json({
1063
440
  status: 'ok',
1064
441
  service: 'agent-deck-mcp-server',
1065
- backendUrl: this.backendUrl
442
+ backendUrl: this.backendUrl,
443
+ toolProfile: this.toolProfile,
1066
444
  });
1067
445
  });
1068
446
  // Backend connectivity check