@nextclaw/mcp 0.1.1 → 0.1.2

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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { McpServerDefinition, McpTransport, Config, McpServerScope } from '@nextclaw/core';
1
+ import { McpServerDefinition, McpTransport, McpServerScope, McpServerMetadata, Config } from '@nextclaw/core';
2
2
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
3
  import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
4
4
 
@@ -45,6 +45,56 @@ type McpLifecycleState = {
45
45
  lastReadyAt?: string;
46
46
  lastError?: string;
47
47
  };
48
+ type McpMarketplaceTransportType = McpTransport["type"];
49
+ type McpMarketplaceInputField = {
50
+ id: string;
51
+ label: string;
52
+ description?: string;
53
+ required?: boolean;
54
+ secret?: boolean;
55
+ defaultValue?: string;
56
+ };
57
+ type McpMarketplaceInstallTemplate = {
58
+ kind: "template";
59
+ spec: string;
60
+ command: string;
61
+ defaultName: string;
62
+ transportTypes: McpMarketplaceTransportType[];
63
+ template: McpServerDefinition;
64
+ inputs: McpMarketplaceInputField[];
65
+ };
66
+ type McpInstalledRecord = {
67
+ name: string;
68
+ enabled: boolean;
69
+ transport: McpTransport["type"];
70
+ scope: McpServerScope;
71
+ source: "manual" | "marketplace";
72
+ catalogSlug?: string;
73
+ displayName?: string;
74
+ vendor?: string;
75
+ docsUrl?: string;
76
+ homepage?: string;
77
+ trustLevel?: "official" | "verified" | "community";
78
+ installedAt?: string;
79
+ toolCount?: number;
80
+ accessible?: boolean;
81
+ lastReadyAt?: string;
82
+ lastError?: string;
83
+ };
84
+ type McpMutationResult = {
85
+ changed: boolean;
86
+ name: string;
87
+ message: string;
88
+ definition?: McpServerDefinition;
89
+ };
90
+ type McpMaterializeInstallParams = {
91
+ template: McpMarketplaceInstallTemplate;
92
+ name?: string;
93
+ enabled?: boolean;
94
+ scope?: Partial<McpServerScope>;
95
+ inputs?: Record<string, string | undefined>;
96
+ metadata?: Partial<McpServerMetadata>;
97
+ };
48
98
  declare function normalizeMcpServerName(name: string): string;
49
99
  declare function readDefaultAgentId(config: Config): string;
50
100
  declare function isServerAccessibleToAgent(params: {
@@ -79,6 +129,7 @@ declare class McpServerLifecycleManager {
79
129
  });
80
130
  warmServer(record: McpServerRecord): Promise<McpLifecycleState>;
81
131
  getCachedCatalog(serverName: string): McpToolCatalogEntry[];
132
+ getCachedState(serverName: string): McpLifecycleState | undefined;
82
133
  callTool(record: McpServerRecord, toolName: string, args: Record<string, unknown>): Promise<unknown>;
83
134
  closeAll(): Promise<void>;
84
135
  closeServer(serverName: string): Promise<void>;
@@ -104,6 +155,7 @@ declare class McpRegistryService {
104
155
  nextConfig: Config;
105
156
  }): Promise<McpConfigReconcileResult>;
106
157
  listAccessibleTools(filter?: McpCatalogFilter): McpToolCatalogEntry[];
158
+ getCachedState(serverName: string): McpLifecycleState | undefined;
107
159
  callTool(params: {
108
160
  serverName: string;
109
161
  toolName: string;
@@ -122,4 +174,55 @@ declare class McpDoctorService {
122
174
  inspect(name?: string): Promise<McpDoctorReport[]>;
123
175
  }
124
176
 
125
- export { type McpCatalogFilter, McpClientFactory, type McpConfigReconcileResult, type McpDoctorReport, McpDoctorService, type McpLifecycleState, McpRegistryService, McpServerLifecycleManager, type McpServerRecord, type McpServerWarmResult, type McpToolCatalogEntry, buildQualifiedMcpToolName, getMcpServer, isServerAccessibleToAgent, listMcpServers, normalizeMcpServerName, readDefaultAgentId, sanitizeMcpSegment };
177
+ declare class McpDoctorFacade {
178
+ private readonly options;
179
+ private readonly doctorService;
180
+ constructor(options: {
181
+ getConfig: () => Config;
182
+ registryService?: McpRegistryService;
183
+ });
184
+ inspect(name?: string): Promise<McpDoctorReport[]>;
185
+ inspectOne(name: string): Promise<McpDoctorReport | null>;
186
+ }
187
+
188
+ declare class McpInstallTemplateMaterializer {
189
+ materialize(params: McpMaterializeInstallParams): {
190
+ name: string;
191
+ definition: McpServerDefinition;
192
+ };
193
+ private applyInputs;
194
+ private mergeScope;
195
+ private mergeMetadata;
196
+ }
197
+
198
+ declare class McpMutationService {
199
+ private readonly options;
200
+ private readonly materializer;
201
+ constructor(options: {
202
+ getConfig: () => Config;
203
+ saveConfig: (config: Config) => void;
204
+ materializer?: McpInstallTemplateMaterializer;
205
+ });
206
+ listServerNames(): string[];
207
+ addServer(name: string, definition: McpServerDefinition): McpMutationResult;
208
+ updateServer(name: string, definition: McpServerDefinition): McpMutationResult;
209
+ removeServer(name: string): McpMutationResult;
210
+ toggleEnabled(name: string, enabled: boolean): McpMutationResult;
211
+ installFromTemplate(params: Omit<McpMaterializeInstallParams, "template"> & {
212
+ template: McpMarketplaceInstallTemplate;
213
+ }): McpMutationResult;
214
+ duplicateServer(sourceName: string, targetName: string): McpMutationResult;
215
+ renameServer(sourceName: string, targetName: string): McpMutationResult;
216
+ }
217
+
218
+ declare class McpInstalledViewService {
219
+ private readonly options;
220
+ private readonly registryService;
221
+ constructor(options: {
222
+ getConfig: () => Config;
223
+ registryService?: McpRegistryService;
224
+ });
225
+ listInstalled(): McpInstalledRecord[];
226
+ }
227
+
228
+ export { type McpCatalogFilter, McpClientFactory, type McpConfigReconcileResult, McpDoctorFacade, type McpDoctorReport, McpDoctorService, McpInstallTemplateMaterializer, type McpInstalledRecord, McpInstalledViewService, type McpLifecycleState, type McpMarketplaceInputField, type McpMarketplaceInstallTemplate, type McpMarketplaceTransportType, type McpMaterializeInstallParams, type McpMutationResult, McpMutationService, McpRegistryService, McpServerLifecycleManager, type McpServerRecord, type McpServerWarmResult, type McpToolCatalogEntry, buildQualifiedMcpToolName, getMcpServer, isServerAccessibleToAgent, listMcpServers, normalizeMcpServerName, readDefaultAgentId, sanitizeMcpSegment };
package/dist/index.js CHANGED
@@ -151,6 +151,13 @@ var McpServerLifecycleManager = class {
151
151
  getCachedCatalog(serverName) {
152
152
  return this.readyConnections.get(serverName)?.tools ?? [];
153
153
  }
154
+ getCachedState(serverName) {
155
+ const ready = this.readyConnections.get(serverName);
156
+ if (!ready) {
157
+ return void 0;
158
+ }
159
+ return this.stripConnection(ready);
160
+ }
154
161
  async callTool(record, toolName, args) {
155
162
  const connection = await this.ensureConnection(record);
156
163
  const result = await connection.client.callTool({
@@ -376,6 +383,9 @@ var McpRegistryService = class {
376
383
  })
377
384
  ).flatMap((record) => this.lifecycleManager.getCachedCatalog(record.name)).sort((left, right) => left.qualifiedName.localeCompare(right.qualifiedName));
378
385
  }
386
+ getCachedState(serverName) {
387
+ return this.lifecycleManager.getCachedState(serverName);
388
+ }
379
389
  async callTool(params) {
380
390
  const server = this.getServer(params.serverName);
381
391
  if (!server) {
@@ -437,9 +447,270 @@ var McpDoctorService = class {
437
447
  );
438
448
  }
439
449
  };
450
+
451
+ // src/doctor/mcp-doctor-facade.ts
452
+ var McpDoctorFacade = class {
453
+ constructor(options) {
454
+ this.options = options;
455
+ this.doctorService = new McpDoctorService({
456
+ getConfig: this.options.getConfig,
457
+ registryService: this.options.registryService
458
+ });
459
+ }
460
+ doctorService;
461
+ async inspect(name) {
462
+ return await this.doctorService.inspect(name);
463
+ }
464
+ async inspectOne(name) {
465
+ const reports = await this.inspect(name);
466
+ return reports[0] ?? null;
467
+ }
468
+ };
469
+
470
+ // src/install/mcp-install-template-materializer.ts
471
+ var McpInstallTemplateMaterializer = class {
472
+ materialize(params) {
473
+ const name = normalizeMcpServerName(params.name?.trim() || params.template.defaultName);
474
+ const inputs = params.inputs ?? {};
475
+ const definition = this.applyInputs(params.template.template, inputs);
476
+ definition.enabled = params.enabled ?? definition.enabled;
477
+ definition.scope = this.mergeScope(definition.scope, params.scope);
478
+ definition.metadata = this.mergeMetadata(definition.metadata, params.template, params.metadata);
479
+ return { name, definition };
480
+ }
481
+ applyInputs(definition, inputs) {
482
+ const replacer = (value) => value.replace(/\{\{\s*([A-Za-z0-9._-]+)\s*\}\}/g, (_, key) => inputs[key]?.trim() ?? "");
483
+ const transform = (value) => {
484
+ if (typeof value === "string") {
485
+ return replacer(value);
486
+ }
487
+ if (Array.isArray(value)) {
488
+ return value.map((entry) => transform(entry));
489
+ }
490
+ if (!value || typeof value !== "object") {
491
+ return value;
492
+ }
493
+ return Object.fromEntries(
494
+ Object.entries(value).map(([key, entry]) => [key, transform(entry)])
495
+ );
496
+ };
497
+ return transform(structuredClone(definition));
498
+ }
499
+ mergeScope(current, override) {
500
+ if (!override) {
501
+ return current;
502
+ }
503
+ const agents = Array.from(new Set((override.agents ?? current.agents ?? []).map((entry) => entry.trim()).filter(Boolean)));
504
+ const allAgents = override.allAgents ?? current.allAgents ?? agents.length === 0;
505
+ return {
506
+ allAgents,
507
+ agents: allAgents ? [] : agents
508
+ };
509
+ }
510
+ mergeMetadata(current, template, override) {
511
+ return {
512
+ ...current,
513
+ source: "marketplace",
514
+ catalogSlug: template.spec,
515
+ displayName: override?.displayName ?? current?.displayName,
516
+ vendor: override?.vendor ?? current?.vendor,
517
+ docsUrl: override?.docsUrl ?? current?.docsUrl,
518
+ homepage: override?.homepage ?? current?.homepage,
519
+ trustLevel: override?.trustLevel ?? current?.trustLevel ?? "official",
520
+ installedAt: override?.installedAt ?? current?.installedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
521
+ ...override ?? {}
522
+ };
523
+ }
524
+ };
525
+
526
+ // src/manage/mcp-mutation-service.ts
527
+ var McpMutationService = class {
528
+ constructor(options) {
529
+ this.options = options;
530
+ this.materializer = this.options.materializer ?? new McpInstallTemplateMaterializer();
531
+ }
532
+ materializer;
533
+ listServerNames() {
534
+ return listMcpServers(this.options.getConfig()).map((record) => record.name);
535
+ }
536
+ addServer(name, definition) {
537
+ const normalizedName = normalizeMcpServerName(name);
538
+ const config = this.options.getConfig();
539
+ if (config.mcp.servers[normalizedName]) {
540
+ return {
541
+ changed: false,
542
+ name: normalizedName,
543
+ message: `MCP server already exists: ${normalizedName}. Use 'mcp list' or remove it first.`,
544
+ definition: config.mcp.servers[normalizedName]
545
+ };
546
+ }
547
+ config.mcp.servers[normalizedName] = definition;
548
+ this.options.saveConfig(config);
549
+ return {
550
+ changed: true,
551
+ name: normalizedName,
552
+ message: `Added MCP server ${normalizedName}.`,
553
+ definition
554
+ };
555
+ }
556
+ updateServer(name, definition) {
557
+ const normalizedName = normalizeMcpServerName(name);
558
+ const config = this.options.getConfig();
559
+ if (!config.mcp.servers[normalizedName]) {
560
+ return {
561
+ changed: false,
562
+ name: normalizedName,
563
+ message: `Unknown MCP server: ${normalizedName}`
564
+ };
565
+ }
566
+ config.mcp.servers[normalizedName] = definition;
567
+ this.options.saveConfig(config);
568
+ return {
569
+ changed: true,
570
+ name: normalizedName,
571
+ message: `Updated MCP server ${normalizedName}.`,
572
+ definition
573
+ };
574
+ }
575
+ removeServer(name) {
576
+ const normalizedName = normalizeMcpServerName(name);
577
+ const config = this.options.getConfig();
578
+ if (!config.mcp.servers[normalizedName]) {
579
+ return {
580
+ changed: false,
581
+ name: normalizedName,
582
+ message: `Unknown MCP server: ${normalizedName}`
583
+ };
584
+ }
585
+ delete config.mcp.servers[normalizedName];
586
+ this.options.saveConfig(config);
587
+ return {
588
+ changed: true,
589
+ name: normalizedName,
590
+ message: `Removed MCP server ${normalizedName}.`
591
+ };
592
+ }
593
+ toggleEnabled(name, enabled) {
594
+ const normalizedName = normalizeMcpServerName(name);
595
+ const config = this.options.getConfig();
596
+ const current = config.mcp.servers[normalizedName];
597
+ if (!current) {
598
+ return {
599
+ changed: false,
600
+ name: normalizedName,
601
+ message: `Unknown MCP server: ${normalizedName}`
602
+ };
603
+ }
604
+ current.enabled = enabled;
605
+ this.options.saveConfig(config);
606
+ return {
607
+ changed: true,
608
+ name: normalizedName,
609
+ message: `${enabled ? "Enabled" : "Disabled"} MCP server ${normalizedName}.`,
610
+ definition: current
611
+ };
612
+ }
613
+ installFromTemplate(params) {
614
+ const materialized = this.materializer.materialize(params);
615
+ return this.addServer(materialized.name, materialized.definition);
616
+ }
617
+ duplicateServer(sourceName, targetName) {
618
+ const source = getMcpServer(this.options.getConfig(), sourceName);
619
+ if (!source) {
620
+ return {
621
+ changed: false,
622
+ name: normalizeMcpServerName(sourceName),
623
+ message: `Unknown MCP server: ${normalizeMcpServerName(sourceName)}`
624
+ };
625
+ }
626
+ const definition = structuredClone(source.definition);
627
+ if (definition.metadata) {
628
+ definition.metadata = {
629
+ ...definition.metadata,
630
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
631
+ };
632
+ }
633
+ return this.addServer(targetName, definition);
634
+ }
635
+ renameServer(sourceName, targetName) {
636
+ const source = getMcpServer(this.options.getConfig(), sourceName);
637
+ if (!source) {
638
+ return {
639
+ changed: false,
640
+ name: normalizeMcpServerName(sourceName),
641
+ message: `Unknown MCP server: ${normalizeMcpServerName(sourceName)}`
642
+ };
643
+ }
644
+ const nextName = normalizeMcpServerName(targetName);
645
+ const config = this.options.getConfig();
646
+ if (source.name === nextName) {
647
+ return {
648
+ changed: false,
649
+ name: nextName,
650
+ message: `MCP server already named ${nextName}.`,
651
+ definition: source.definition
652
+ };
653
+ }
654
+ if (config.mcp.servers[nextName]) {
655
+ return {
656
+ changed: false,
657
+ name: nextName,
658
+ message: `MCP server already exists: ${nextName}. Use another name.`
659
+ };
660
+ }
661
+ delete config.mcp.servers[source.name];
662
+ config.mcp.servers[nextName] = source.definition;
663
+ this.options.saveConfig(config);
664
+ return {
665
+ changed: true,
666
+ name: nextName,
667
+ message: `Renamed MCP server ${source.name} -> ${nextName}.`,
668
+ definition: source.definition
669
+ };
670
+ }
671
+ };
672
+
673
+ // src/view/mcp-installed-view-service.ts
674
+ var McpInstalledViewService = class {
675
+ constructor(options) {
676
+ this.options = options;
677
+ this.registryService = this.options.registryService ?? new McpRegistryService({
678
+ getConfig: this.options.getConfig
679
+ });
680
+ }
681
+ registryService;
682
+ listInstalled() {
683
+ return this.registryService.listServers().map((server) => {
684
+ const metadata = server.definition.metadata;
685
+ const cached = this.registryService.getCachedState(server.name);
686
+ return {
687
+ name: server.name,
688
+ enabled: server.definition.enabled,
689
+ transport: server.definition.transport.type,
690
+ scope: server.definition.scope,
691
+ source: metadata?.source === "marketplace" ? "marketplace" : "manual",
692
+ catalogSlug: metadata?.catalogSlug,
693
+ displayName: metadata?.displayName,
694
+ vendor: metadata?.vendor,
695
+ docsUrl: metadata?.docsUrl,
696
+ homepage: metadata?.homepage,
697
+ trustLevel: metadata?.trustLevel,
698
+ installedAt: metadata?.installedAt,
699
+ accessible: cached?.clientReady,
700
+ toolCount: cached?.tools.length,
701
+ lastReadyAt: cached?.lastReadyAt,
702
+ lastError: cached?.lastError
703
+ };
704
+ });
705
+ }
706
+ };
440
707
  export {
441
708
  McpClientFactory,
709
+ McpDoctorFacade,
442
710
  McpDoctorService,
711
+ McpInstallTemplateMaterializer,
712
+ McpInstalledViewService,
713
+ McpMutationService,
443
714
  McpRegistryService,
444
715
  McpServerLifecycleManager,
445
716
  buildQualifiedMcpToolName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "description": "Platform-level MCP registry, lifecycle, and diagnostics for NextClaw.",
6
6
  "type": "module",