@arcbridge/mcp-server 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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @arcbridge/mcp-server
2
2
 
3
- MCP server for ArcBridge — exposes 26 architecture tools to AI coding agents via the [Model Context Protocol](https://modelcontextprotocol.io).
3
+ MCP server for ArcBridge — exposes 29 architecture tools to AI coding agents via the [Model Context Protocol](https://modelcontextprotocol.io).
4
4
 
5
5
  ## Install
6
6
 
@@ -88,6 +88,14 @@ Restart your AI agent (Claude Code, etc.) and approve the MCP server when prompt
88
88
  | `arcbridge_verify_scenarios` | Run linked tests for quality scenarios |
89
89
  | `arcbridge_run_role_check` | Run a role's quality checks against code |
90
90
 
91
+ ### Metrics
92
+
93
+ | Tool | Description |
94
+ |------|-------------|
95
+ | `arcbridge_record_activity` | Record agent activity — model, tokens, cost, duration, quality snapshot |
96
+ | `arcbridge_get_metrics` | Query and aggregate activity by model, task, phase, tool, or day |
97
+ | `arcbridge_export_metrics` | Export metrics to JSON, CSV, or Markdown for git commits |
98
+
91
99
  ## How It Works
92
100
 
93
101
  The server communicates over stdio using the MCP protocol. Each tool call receives a `target_dir` parameter pointing to an ArcBridge-initialized project. The server manages a SQLite database (`.arcbridge/index.db`) that caches architecture docs, indexed symbols, and planning state.
package/dist/index.js CHANGED
@@ -149,7 +149,7 @@ import { refreshFromDocs } from "@arcbridge/core";
149
149
  // src/helpers.ts
150
150
  import { join as join2 } from "path";
151
151
  import { existsSync as existsSync2 } from "fs";
152
- import { openDatabase } from "@arcbridge/core";
152
+ import { openDatabase, migrate } from "@arcbridge/core";
153
153
  function ensureDb(ctx, targetDir) {
154
154
  if (ctx.db) return ctx.db;
155
155
  const dbPath = join2(targetDir, ".arcbridge", "index.db");
@@ -157,6 +157,7 @@ function ensureDb(ctx, targetDir) {
157
157
  return null;
158
158
  }
159
159
  ctx.db = openDatabase(dbPath);
160
+ migrate(ctx.db);
160
161
  ctx.projectRoot = targetDir;
161
162
  return ctx.db;
162
163
  }
@@ -762,6 +763,42 @@ function registerGetCurrentTasks(server, ctx) {
762
763
  // src/tools/update-task.ts
763
764
  import { z as z8 } from "zod";
764
765
  import { syncTaskToYaml } from "@arcbridge/core";
766
+
767
+ // src/auto-record.ts
768
+ import { loadConfig, insertActivity } from "@arcbridge/core";
769
+ var configCache = /* @__PURE__ */ new Map();
770
+ var CACHE_TTL_MS = 3e4;
771
+ function isAutoRecordEnabled(projectRoot) {
772
+ const cached = configCache.get(projectRoot);
773
+ if (cached && Date.now() - cached.loadedAt < CACHE_TTL_MS) {
774
+ return cached.autoRecord;
775
+ }
776
+ const { config } = loadConfig(projectRoot);
777
+ const autoRecord2 = config?.metrics?.auto_record ?? false;
778
+ configCache.set(projectRoot, { autoRecord: autoRecord2, loadedAt: Date.now() });
779
+ return autoRecord2;
780
+ }
781
+ function autoRecord(db, projectRoot, params) {
782
+ try {
783
+ if (!isAutoRecordEnabled(projectRoot)) return;
784
+ insertActivity(db, {
785
+ toolName: params.toolName,
786
+ action: params.action,
787
+ taskId: params.taskId,
788
+ phaseId: params.phaseId,
789
+ durationMs: params.durationMs,
790
+ driftCount: params.driftCount,
791
+ driftErrors: params.driftErrors,
792
+ testPassCount: params.testPassCount,
793
+ testFailCount: params.testFailCount,
794
+ lintClean: params.lintClean,
795
+ typecheckClean: params.typecheckClean
796
+ });
797
+ } catch {
798
+ }
799
+ }
800
+
801
+ // src/tools/update-task.ts
765
802
  function registerUpdateTask(server, ctx) {
766
803
  server.tool(
767
804
  "arcbridge_update_task",
@@ -773,6 +810,7 @@ function registerUpdateTask(server, ctx) {
773
810
  notes: z8.string().optional().describe("Optional notes about the status change")
774
811
  },
775
812
  async (params) => {
813
+ const start = Date.now();
776
814
  const db = ensureDb(ctx, params.target_dir);
777
815
  if (!db) return notInitialized();
778
816
  const task = db.prepare("SELECT id, title, status, phase_id FROM tasks WHERE id = ?").get(params.task_id);
@@ -828,6 +866,13 @@ function registerUpdateTask(server, ctx) {
828
866
  );
829
867
  }
830
868
  }
869
+ autoRecord(db, params.target_dir, {
870
+ toolName: "arcbridge_update_task",
871
+ action: `${task.id}: ${oldStatus} \u2192 ${params.status}`,
872
+ taskId: params.task_id,
873
+ phaseId: task.phase_id,
874
+ durationMs: Date.now() - start
875
+ });
831
876
  return {
832
877
  content: [{ type: "text", text: lines.join("\n") }]
833
878
  };
@@ -1018,7 +1063,7 @@ import { indexProject as indexProject2, refreshFromDocs as refreshFromDocs4 } fr
1018
1063
  function registerReindex(server, ctx) {
1019
1064
  server.tool(
1020
1065
  "arcbridge_reindex",
1021
- "Re-index code symbols in the project. Supports TypeScript and C# (.NET). Incrementally processes only changed files.",
1066
+ "Re-index the project: refreshes architecture docs from arc42/YAML files, then reindexes code symbols (TypeScript & C#/.NET). This is the first step of the sync pipeline \u2014 use it to pick up manual doc edits and code changes.",
1022
1067
  {
1023
1068
  target_dir: z11.string().describe("Absolute path to the project directory"),
1024
1069
  tsconfig_path: z11.string().optional().describe("Override tsconfig.json path (default: auto-detect). Only used for TypeScript projects."),
@@ -1026,6 +1071,7 @@ function registerReindex(server, ctx) {
1026
1071
  language: z11.enum(["typescript", "csharp", "auto"]).optional().describe("Project language. 'auto' detects from project files (default: 'auto')")
1027
1072
  },
1028
1073
  async (params) => {
1074
+ const start = Date.now();
1029
1075
  const db = ensureDb(ctx, params.target_dir);
1030
1076
  if (!db) return notInitialized();
1031
1077
  try {
@@ -1049,6 +1095,11 @@ function registerReindex(server, ctx) {
1049
1095
  `- **Routes analyzed:** ${result.routesAnalyzed}`,
1050
1096
  `- **Duration:** ${result.durationMs}ms`
1051
1097
  ];
1098
+ autoRecord(db, params.target_dir, {
1099
+ toolName: "arcbridge_reindex",
1100
+ action: `${result.symbolsIndexed} symbols, ${result.filesProcessed} files`,
1101
+ durationMs: Date.now() - start
1102
+ });
1052
1103
  return textResult(lines.join("\n"));
1053
1104
  } catch (err) {
1054
1105
  const message = err instanceof Error ? err.message : String(err);
@@ -1760,6 +1811,7 @@ function registerCheckDrift(server, ctx) {
1760
1811
  persist: z18.boolean().default(true).describe("Write findings to drift_log table (default: true)")
1761
1812
  },
1762
1813
  async (params) => {
1814
+ const start = Date.now();
1763
1815
  const db = ensureDb(ctx, params.target_dir);
1764
1816
  if (!db) return notInitialized();
1765
1817
  const entries = detectDrift(db);
@@ -1815,6 +1867,13 @@ function registerCheckDrift(server, ctx) {
1815
1867
  ""
1816
1868
  );
1817
1869
  }
1870
+ autoRecord(db, params.target_dir, {
1871
+ toolName: "arcbridge_check_drift",
1872
+ action: `${entries.length} issues (${errors} errors)`,
1873
+ driftCount: entries.length,
1874
+ driftErrors: errors,
1875
+ durationMs: Date.now() - start
1876
+ });
1818
1877
  return textResult(lines.join("\n"));
1819
1878
  }
1820
1879
  );
@@ -2652,7 +2711,7 @@ import {
2652
2711
  inferTaskStatuses,
2653
2712
  applyInferences,
2654
2713
  verifyScenarios,
2655
- loadConfig,
2714
+ loadConfig as loadConfig2,
2656
2715
  refreshFromDocs as refreshFromDocs5,
2657
2716
  syncPhaseToYaml
2658
2717
  } from "@arcbridge/core";
@@ -2668,6 +2727,7 @@ function registerCompletePhase(server, ctx) {
2668
2727
  run_tests: z23.boolean().default(false).describe("Run linked tests for quality scenarios before checking the quality gate")
2669
2728
  },
2670
2729
  async (params) => {
2730
+ const start = Date.now();
2671
2731
  const db = ensureDb(ctx, params.target_dir);
2672
2732
  if (!db) return notInitialized();
2673
2733
  refreshFromDocs5(db, params.target_dir);
@@ -2715,7 +2775,7 @@ function registerCompletePhase(server, ctx) {
2715
2775
  const projectRoot = ctx.projectRoot ?? params.target_dir;
2716
2776
  let testCommand = "npx vitest run";
2717
2777
  let timeoutMs = 6e4;
2718
- const configResult = loadConfig(params.target_dir);
2778
+ const configResult = loadConfig2(params.target_dir);
2719
2779
  if (configResult.config) {
2720
2780
  testCommand = configResult.config.testing.test_command;
2721
2781
  timeoutMs = configResult.config.testing.timeout_ms;
@@ -2868,6 +2928,12 @@ function registerCompletePhase(server, ctx) {
2868
2928
  "Resolve the issues above before completing this phase."
2869
2929
  );
2870
2930
  }
2931
+ autoRecord(db, params.target_dir, {
2932
+ toolName: "arcbridge_complete_phase",
2933
+ action: `${phase.name}: ${allPass ? "PASSED" : "BLOCKED"}`,
2934
+ phaseId: params.phase_id,
2935
+ durationMs: Date.now() - start
2936
+ });
2871
2937
  return textResult(lines.join("\n"));
2872
2938
  }
2873
2939
  );
@@ -3188,7 +3254,7 @@ function getRoleDefinition(roleId) {
3188
3254
 
3189
3255
  // src/tools/verify-scenarios.ts
3190
3256
  import { z as z25 } from "zod";
3191
- import { verifyScenarios as verifyScenarios2, loadConfig as loadConfig2 } from "@arcbridge/core";
3257
+ import { verifyScenarios as verifyScenarios2, loadConfig as loadConfig3 } from "@arcbridge/core";
3192
3258
  function registerVerifyScenarios(server, ctx) {
3193
3259
  server.tool(
3194
3260
  "arcbridge_verify_scenarios",
@@ -3207,7 +3273,7 @@ function registerVerifyScenarios(server, ctx) {
3207
3273
  if (!db) return notInitialized();
3208
3274
  let testCommand = "npx vitest run";
3209
3275
  let timeoutMs = 6e4;
3210
- const configResult = loadConfig2(params.target_dir);
3276
+ const configResult = loadConfig3(params.target_dir);
3211
3277
  if (configResult.config) {
3212
3278
  testCommand = configResult.config.testing.test_command;
3213
3279
  timeoutMs = configResult.config.testing.timeout_ms;
@@ -3702,6 +3768,232 @@ function runCustomRoleCheck(db, lines, roleDef) {
3702
3768
  appendDriftSection(db, lines);
3703
3769
  }
3704
3770
 
3771
+ // src/tools/record-activity.ts
3772
+ import { z as z27 } from "zod";
3773
+ import { insertActivity as insertActivity2, getSessionTotals } from "@arcbridge/core";
3774
+ function registerRecordActivity(server, ctx) {
3775
+ server.tool(
3776
+ "arcbridge_record_activity",
3777
+ "Record agent activity \u2014 model, tokens, cost, duration, and optional quality snapshot. Use this to track what work was done and measure agent performance.",
3778
+ {
3779
+ target_dir: z27.string().describe("Absolute path to the project directory"),
3780
+ tool_name: z27.string().describe("Name of the tool or action performed (e.g., 'arcbridge_update_task', 'code_edit')"),
3781
+ action: z27.string().optional().describe("Human-readable label (e.g., 'implement login form')"),
3782
+ model: z27.string().optional().describe("Model identifier (e.g., 'claude-sonnet-4-20250514')"),
3783
+ agent_role: z27.string().optional().describe("Active ArcBridge role (e.g., 'implementer')"),
3784
+ task_id: z27.string().optional().describe("Associated task ID"),
3785
+ phase_id: z27.string().optional().describe("Associated phase ID"),
3786
+ input_tokens: z27.number().int().nonnegative().optional().describe("Input/prompt tokens"),
3787
+ output_tokens: z27.number().int().nonnegative().optional().describe("Output/completion tokens"),
3788
+ total_tokens: z27.number().int().nonnegative().optional().describe("Total tokens (auto-computed if input+output given)"),
3789
+ cost_usd: z27.number().nonnegative().optional().describe("Estimated cost in USD"),
3790
+ duration_ms: z27.number().int().nonnegative().optional().describe("Wall-clock duration in ms"),
3791
+ drift_count: z27.number().int().nonnegative().optional().describe("Current drift count"),
3792
+ drift_errors: z27.number().int().nonnegative().optional().describe("Current drift errors"),
3793
+ test_pass_count: z27.number().int().nonnegative().optional().describe("Passing tests"),
3794
+ test_fail_count: z27.number().int().nonnegative().optional().describe("Failing tests"),
3795
+ lint_clean: z27.boolean().optional().describe("Whether lint passes cleanly"),
3796
+ typecheck_clean: z27.boolean().optional().describe("Whether typecheck passes cleanly"),
3797
+ notes: z27.string().optional().describe("Free-form notes"),
3798
+ metadata: z27.record(z27.unknown()).optional().describe("Additional key-value metadata")
3799
+ },
3800
+ async (params) => {
3801
+ const db = ensureDb(ctx, params.target_dir);
3802
+ if (!db) return notInitialized();
3803
+ const rowId = insertActivity2(db, {
3804
+ toolName: params.tool_name,
3805
+ action: params.action,
3806
+ model: params.model,
3807
+ agentRole: params.agent_role,
3808
+ taskId: params.task_id,
3809
+ phaseId: params.phase_id,
3810
+ inputTokens: params.input_tokens,
3811
+ outputTokens: params.output_tokens,
3812
+ totalTokens: params.total_tokens,
3813
+ costUsd: params.cost_usd,
3814
+ durationMs: params.duration_ms,
3815
+ driftCount: params.drift_count,
3816
+ driftErrors: params.drift_errors,
3817
+ testPassCount: params.test_pass_count,
3818
+ testFailCount: params.test_fail_count,
3819
+ lintClean: params.lint_clean,
3820
+ typecheckClean: params.typecheck_clean,
3821
+ notes: params.notes,
3822
+ metadata: params.metadata
3823
+ });
3824
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3825
+ const totals = getSessionTotals(db, today, params.model);
3826
+ const totalTokens = params.total_tokens ?? (params.input_tokens != null && params.output_tokens != null ? params.input_tokens + params.output_tokens : null);
3827
+ const lines = [
3828
+ `# Activity Recorded (#${rowId})`,
3829
+ "",
3830
+ `- **Tool:** ${params.tool_name}`
3831
+ ];
3832
+ if (params.action) lines.push(`- **Action:** ${params.action}`);
3833
+ if (params.model) lines.push(`- **Model:** ${params.model}`);
3834
+ if (totalTokens != null) {
3835
+ const detail = params.input_tokens != null && params.output_tokens != null ? `${params.input_tokens.toLocaleString()} in / ${params.output_tokens.toLocaleString()} out (${totalTokens.toLocaleString()} total)` : `${totalTokens.toLocaleString()} total`;
3836
+ lines.push(`- **Tokens:** ${detail}`);
3837
+ }
3838
+ if (params.cost_usd != null) lines.push(`- **Cost:** $${params.cost_usd.toFixed(4)}`);
3839
+ if (params.duration_ms != null) lines.push(`- **Duration:** ${params.duration_ms.toLocaleString()}ms`);
3840
+ lines.push(
3841
+ "",
3842
+ `## Session Totals (today${params.model ? `, ${params.model}` : ""})`,
3843
+ `- **Total cost:** $${totals.totalCost.toFixed(4)}`,
3844
+ `- **Total tokens:** ${totals.totalTokens.toLocaleString()}`,
3845
+ `- **Activities recorded:** ${totals.activityCount}`
3846
+ );
3847
+ return textResult(lines.join("\n"));
3848
+ }
3849
+ );
3850
+ }
3851
+
3852
+ // src/tools/get-metrics.ts
3853
+ import { z as z28 } from "zod";
3854
+ import { queryMetrics } from "@arcbridge/core";
3855
+ function registerGetMetrics(server, ctx) {
3856
+ server.tool(
3857
+ "arcbridge_get_metrics",
3858
+ "Query agent activity metrics \u2014 filter by model, task, phase, or time range. Group by model/task/phase/tool/day for aggregated views.",
3859
+ {
3860
+ target_dir: z28.string().describe("Absolute path to the project directory"),
3861
+ task_id: z28.string().optional().describe("Filter by task ID"),
3862
+ phase_id: z28.string().optional().describe("Filter by phase ID"),
3863
+ model: z28.string().optional().describe("Filter by model name"),
3864
+ agent_role: z28.string().optional().describe("Filter by agent role"),
3865
+ tool_name: z28.string().optional().describe("Filter by tool name"),
3866
+ since: z28.string().optional().describe("ISO 8601 timestamp \u2014 activity after this time"),
3867
+ until: z28.string().optional().describe("ISO 8601 timestamp \u2014 activity before this time"),
3868
+ group_by: z28.enum(["model", "task", "phase", "tool", "day", "none"]).default("none").describe("Group results for aggregation"),
3869
+ limit: z28.number().int().min(1).max(500).default(50).describe("Max rows in detail view (group_by=none)")
3870
+ },
3871
+ async (params) => {
3872
+ const db = ensureDb(ctx, params.target_dir);
3873
+ if (!db) return notInitialized();
3874
+ const result = queryMetrics(db, {
3875
+ taskId: params.task_id,
3876
+ phaseId: params.phase_id,
3877
+ model: params.model,
3878
+ agentRole: params.agent_role,
3879
+ toolName: params.tool_name,
3880
+ since: params.since,
3881
+ until: params.until,
3882
+ groupBy: params.group_by,
3883
+ limit: params.limit
3884
+ });
3885
+ if (result.totals.activityCount === 0) {
3886
+ return textResult("No agent activity recorded yet. Use `arcbridge_record_activity` to log agent work.");
3887
+ }
3888
+ const lines = [];
3889
+ if (result.grouped) {
3890
+ const rows = result.rows;
3891
+ lines.push(
3892
+ `# Agent Metrics (grouped by ${params.group_by})`,
3893
+ "",
3894
+ `| ${capitalize(params.group_by)} | Activities | Total Tokens | Avg Tokens | Total Cost | Avg Duration |`,
3895
+ `|${"-".repeat(20)}|-----------|-------------|-----------|-----------|-------------|`
3896
+ );
3897
+ for (const r of rows) {
3898
+ lines.push(
3899
+ `| ${mdCell(r.groupKey)} | ${r.activityCount} | ${r.sumTokens?.toLocaleString() ?? "-"} | ${r.avgTokens?.toLocaleString() ?? "-"} | ${r.sumCost != null ? "$" + r.sumCost.toFixed(4) : "-"} | ${r.avgDuration != null ? Math.round(r.avgDuration) + "ms" : "-"} |`
3900
+ );
3901
+ }
3902
+ } else {
3903
+ const rows = result.rows;
3904
+ lines.push(
3905
+ "# Agent Activity (recent)",
3906
+ "",
3907
+ "| Time | Tool | Action | Model | Tokens | Cost | Duration |",
3908
+ "|------|------|--------|-------|--------|------|----------|"
3909
+ );
3910
+ for (const r of rows) {
3911
+ lines.push(
3912
+ `| ${r.recorded_at.slice(0, 19)} | ${mdCell(r.tool_name)} | ${mdCell(r.action)} | ${mdCell(r.model)} | ${r.total_tokens?.toLocaleString() ?? ""} | ${r.cost_usd != null ? "$" + r.cost_usd.toFixed(4) : ""} | ${r.duration_ms != null ? r.duration_ms.toLocaleString() + "ms" : ""} |`
3913
+ );
3914
+ }
3915
+ }
3916
+ const q = result.qualitySnapshot;
3917
+ if (q.capturedAt) {
3918
+ lines.push(
3919
+ "",
3920
+ "## Latest Quality Snapshot",
3921
+ ""
3922
+ );
3923
+ if (q.driftCount != null) lines.push(`- **Drift:** ${q.driftCount} issues (${q.driftErrors ?? 0} errors)`);
3924
+ if (q.testPassCount != null) lines.push(`- **Tests:** ${q.testPassCount} pass / ${q.testFailCount ?? 0} fail`);
3925
+ if (q.lintClean != null) lines.push(`- **Lint:** ${q.lintClean ? "clean" : "errors"}`);
3926
+ if (q.typecheckClean != null) lines.push(`- **Typecheck:** ${q.typecheckClean ? "clean" : "errors"}`);
3927
+ }
3928
+ lines.push(
3929
+ "",
3930
+ "## Totals",
3931
+ "",
3932
+ `- **Activities:** ${result.totals.activityCount}`,
3933
+ `- **Total cost:** $${result.totals.totalCost.toFixed(4)}`,
3934
+ `- **Total tokens:** ${result.totals.totalTokens.toLocaleString()}`
3935
+ );
3936
+ if (result.timeSpan) {
3937
+ lines.push(`- **Time span:** ${result.timeSpan.first.slice(0, 10)} \u2192 ${result.timeSpan.last.slice(0, 10)}`);
3938
+ }
3939
+ return textResult(lines.join("\n"));
3940
+ }
3941
+ );
3942
+ }
3943
+ function capitalize(s) {
3944
+ return s.charAt(0).toUpperCase() + s.slice(1);
3945
+ }
3946
+ function mdCell(val) {
3947
+ if (val == null) return "";
3948
+ return val.replace(/\|/g, "\\|").replace(/\r?\n|\r/g, " ");
3949
+ }
3950
+
3951
+ // src/tools/export-metrics.ts
3952
+ import { z as z29 } from "zod";
3953
+ import { exportMetrics } from "@arcbridge/core";
3954
+ function registerExportMetrics(server, ctx) {
3955
+ server.tool(
3956
+ "arcbridge_export_metrics",
3957
+ "Export agent activity metrics to a file (JSON, CSV, or Markdown) in .arcbridge/metrics/ for git commits or reporting.",
3958
+ {
3959
+ target_dir: z29.string().describe("Absolute path to the project directory"),
3960
+ format: z29.enum(["json", "csv", "markdown"]).default("json").describe("Export format"),
3961
+ task_id: z29.string().optional().describe("Filter by task ID"),
3962
+ phase_id: z29.string().optional().describe("Filter by phase ID"),
3963
+ model: z29.string().optional().describe("Filter by model name"),
3964
+ agent_role: z29.string().optional().describe("Filter by agent role"),
3965
+ tool_name: z29.string().optional().describe("Filter by tool name"),
3966
+ since: z29.string().optional().describe("ISO 8601 \u2014 activity after this time"),
3967
+ until: z29.string().optional().describe("ISO 8601 \u2014 activity before this time"),
3968
+ max_rows: z29.number().int().min(1).default(1e5).describe("Maximum rows to export (default: 100,000)")
3969
+ },
3970
+ async (params) => {
3971
+ const db = ensureDb(ctx, params.target_dir);
3972
+ if (!db) return notInitialized();
3973
+ const filePath = exportMetrics(
3974
+ db,
3975
+ params.target_dir,
3976
+ params.format,
3977
+ {
3978
+ taskId: params.task_id,
3979
+ phaseId: params.phase_id,
3980
+ model: params.model,
3981
+ agentRole: params.agent_role,
3982
+ toolName: params.tool_name,
3983
+ since: params.since,
3984
+ until: params.until
3985
+ },
3986
+ params.max_rows
3987
+ );
3988
+ return textResult(
3989
+ `Metrics exported to: ${filePath}
3990
+
3991
+ You can commit this file to preserve the activity record in git.`
3992
+ );
3993
+ }
3994
+ );
3995
+ }
3996
+
3705
3997
  // src/server.ts
3706
3998
  var require2 = createRequire(import.meta.url);
3707
3999
  var { version } = require2("../package.json");
@@ -3737,6 +4029,9 @@ function createArcBridgeServer() {
3737
4029
  registerActivateRole(server, ctx);
3738
4030
  registerVerifyScenarios(server, ctx);
3739
4031
  registerRunRoleCheck(server, ctx);
4032
+ registerRecordActivity(server, ctx);
4033
+ registerGetMetrics(server, ctx);
4034
+ registerExportMetrics(server, ctx);
3740
4035
  return server;
3741
4036
  }
3742
4037