@gethmy/mcp 2.2.0 → 2.2.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/src/server.ts CHANGED
@@ -59,13 +59,7 @@ import {
59
59
  } from "./context-assembly.js";
60
60
  import { autoExpandGraph } from "./graph-expansion.js";
61
61
  import { runLifecycleMaintenance } from "./lifecycle-maintenance.js";
62
- import {
63
- type CardData,
64
- type ColumnData,
65
- generatePrompt,
66
- type MemoryData,
67
- type PromptVariant,
68
- } from "./prompt-builder.js";
62
+ import type { PromptVariant } from "./prompt-builder.js";
69
63
 
70
64
  /**
71
65
  * Dependencies injected into tool handlers.
@@ -2699,14 +2693,11 @@ async function handleToolCall(
2699
2693
 
2700
2694
  // Prompt generation
2701
2695
  case "harmony_generate_prompt": {
2702
- // Get card - either by UUID or short ID
2703
- let cardData: CardData;
2704
- let columnData: ColumnData | null = null;
2696
+ // Resolve card ID either directly or via short ID
2697
+ let cardId: string;
2705
2698
 
2706
2699
  if (args.cardId) {
2707
- const cardId = z.string().uuid().parse(args.cardId);
2708
- const cardResult = await client.getCard(cardId);
2709
- cardData = cardResult.card as CardData;
2700
+ cardId = z.string().uuid().parse(args.cardId);
2710
2701
  } else if (args.shortId !== undefined) {
2711
2702
  const shortId = z.number().int().positive().parse(args.shortId);
2712
2703
  const projectId =
@@ -2717,35 +2708,12 @@ async function handleToolCall(
2717
2708
  );
2718
2709
  }
2719
2710
  const cardResult = await client.getCardByShortId(projectId, shortId);
2720
- cardData = cardResult.card as CardData;
2711
+ cardId = (cardResult.card as { id: string }).id;
2721
2712
  } else {
2722
2713
  throw new Error("Either cardId or shortId must be provided");
2723
2714
  }
2724
2715
 
2725
- // Try to get column info from board
2726
- const projectIdForBoard =
2727
- (args.projectId as string) ||
2728
- getActiveProjectId() ||
2729
- (cardData as unknown as { project_id: string }).project_id;
2730
- if (projectIdForBoard) {
2731
- try {
2732
- const board = await client.getBoard(projectIdForBoard, {
2733
- summary: true,
2734
- });
2735
- const columnId = (cardData as unknown as { column_id: string })
2736
- .column_id;
2737
- const column = (
2738
- board.columns as Array<{ id: string; name: string }>
2739
- ).find((col) => col.id === columnId);
2740
- if (column) {
2741
- columnData = { name: column.name };
2742
- }
2743
- } catch {
2744
- // Column info not available, continue without it
2745
- }
2746
- }
2747
-
2748
- const variant = (args.variant as PromptVariant) || "execute";
2716
+ // Parse MCP-specific context options
2749
2717
  const contextOptions: Record<string, boolean> = {};
2750
2718
  if (args.includeSubtasks !== undefined) {
2751
2719
  contextOptions.includeSubtasks =
@@ -2761,89 +2729,24 @@ async function handleToolCall(
2761
2729
  args.includeDescription === "true";
2762
2730
  }
2763
2731
 
2764
- // Assemble context using the context assembly engine
2765
- let assembledContextStr: string | undefined;
2766
- let assemblyId: string | undefined;
2767
- let memories: MemoryData[] | undefined;
2768
-
2769
- try {
2770
- const workspaceId = deps.getActiveWorkspaceId();
2771
- if (workspaceId && cardData.title) {
2772
- const cardLabels = (cardData.labels || []).map((l) => l.name);
2773
- const taskContext = [cardData.title, cardData.description || ""]
2774
- .filter(Boolean)
2775
- .join(" ");
2776
-
2777
- const assembled = await assembleContext({
2778
- workspaceId,
2779
- projectId: getActiveProjectId() || undefined,
2780
- taskContext,
2781
- cardLabels,
2782
- cardId: cardData.id,
2783
- client,
2784
- });
2785
-
2786
- if (assembled.context) {
2787
- assembledContextStr = assembled.context;
2788
- assemblyId = assembled.manifest.assemblyId;
2789
- cacheManifest(assembled.manifest);
2790
- }
2791
- }
2792
- } catch {
2793
- // Context assembly failed, try legacy fallback
2794
- try {
2795
- const workspaceId = deps.getActiveWorkspaceId();
2796
- if (workspaceId && cardData.title) {
2797
- const memoryResult = await client.searchMemoryEntities(
2798
- workspaceId,
2799
- cardData.title,
2800
- {
2801
- project_id: getActiveProjectId() || undefined,
2802
- limit: 5,
2803
- },
2804
- );
2805
- if (memoryResult.entities?.length > 0) {
2806
- memories = memoryResult.entities.map((e: unknown) => {
2807
- const entity = e as {
2808
- id: string;
2809
- type: string;
2810
- title: string;
2811
- content: string;
2812
- confidence: number;
2813
- tags: string[];
2814
- };
2815
- return {
2816
- id: entity.id,
2817
- type: entity.type,
2818
- title: entity.title,
2819
- content: entity.content,
2820
- confidence: entity.confidence,
2821
- tags: entity.tags || [],
2822
- };
2823
- });
2824
- }
2825
- }
2826
- } catch {
2827
- // Memory fetch also failed, continue without memories
2828
- }
2829
- }
2830
-
2831
- const result = generatePrompt({
2832
- card: cardData,
2833
- column: columnData,
2834
- variant,
2835
- contextOptions,
2732
+ // Delegate to the shared prompt generation pipeline
2733
+ const result = await client.generateCardPrompt({
2734
+ cardId,
2735
+ workspaceId: deps.getActiveWorkspaceId() || "",
2736
+ projectId:
2737
+ (args.projectId as string) || getActiveProjectId() || undefined,
2738
+ variant: (args.variant as PromptVariant) || "execute",
2836
2739
  customConstraints: args.customConstraints as string | undefined,
2837
- memories,
2838
- assembledContext: assembledContextStr,
2839
- assemblyId,
2740
+ contextOptions,
2840
2741
  });
2841
2742
 
2743
+ // MCP-specific: cache the assembly manifest for the feedback loop
2744
+ if (result.assemblyId) {
2745
+ trackSessionAssembly(cardId, result.assemblyId);
2746
+ }
2747
+
2842
2748
  return {
2843
2749
  success: true,
2844
- cardId: cardData.id,
2845
- shortId: cardData.short_id,
2846
- title: cardData.title,
2847
2750
  ...result,
2848
2751
  };
2849
2752
  }
@@ -3037,8 +2940,7 @@ async function handleToolCall(
3037
2940
  // Track memory write action and flush (fire-and-forget)
3038
2941
  const updateMemSession = getActiveMemorySession();
3039
2942
  if (updateMemSession) {
3040
- const updateTitle =
3041
- (updates.title as string) || entityId.slice(0, 8);
2943
+ const updateTitle = (updates.title as string) || entityId.slice(0, 8);
3042
2944
  appendMemoryAction(
3043
2945
  updateMemSession.cardId,
3044
2946
  `Updated memory: ${updateTitle}`,
@@ -4053,13 +3955,17 @@ export class HarmonyMCPServer {
4053
3955
  await this.server.connect(transport);
4054
3956
  console.error("Harmony MCP server running on stdio");
4055
3957
 
4056
- // Initialize auto-session tracking
3958
+ // Initialize auto-session tracking with MCP client identity detection
4057
3959
  const configDeps = createConfigDeps();
4058
3960
  initAutoSession(
4059
3961
  async (client, cardId, status) => {
4060
3962
  await runEndSessionPipeline(client, configDeps, cardId, status);
4061
3963
  },
4062
3964
  () => getClient(),
3965
+ () => {
3966
+ const cv = this.server.getClientVersion();
3967
+ return cv ? { name: cv.name, version: cv.version } : null;
3968
+ },
4063
3969
  );
4064
3970
 
4065
3971
  // Graceful shutdown: end all auto-sessions