@surfil/mcp 3.6.6

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 ADDED
@@ -0,0 +1,68 @@
1
+ # surfil-mcp
2
+
3
+ > **Note:** The live npm package name is `surfil-mcp-server` (the `surfil-mcp` name is in a 24h npm republish lock after an accidental unpublish · it will be restored as the canonical name once the lock expires). Install with `npm i -g surfil-mcp-server` or use `npx -y surfil-mcp-server@latest`.
4
+
5
+ **Surfil MCP server** — published on npm as `surfil-mcp` for automatic AI session tracking across official Surfil adapters.
6
+
7
+ Once connected, Surfil automatically:
8
+ - Opens a session when your AI tool starts
9
+ - Tracks tool usage throughout the session
10
+ - Closes the session when your AI tool exits
11
+ - Displays everything on your [Surfil dashboard](https://surfil.com/dashboard)
12
+
13
+ ## Install
14
+
15
+ `surfil-mcp` is normally installed for you automatically via the Surfil CLI:
16
+
17
+ ```bash
18
+ surfil connect <tool>
19
+ ```
20
+
21
+ Supported official adapters:
22
+ - `claude-code`
23
+ - `cursor`
24
+ - `vscode`
25
+ - `windsurf`
26
+ - `jetbrains`
27
+ - `opencode`
28
+ - `neovim`
29
+ - `copilot`
30
+ - `continue`
31
+ - `codex`
32
+ - `gemini-cli`
33
+ - `aider`
34
+ - `zed`
35
+ - `warp`
36
+ - `roo`
37
+ - `cline`
38
+ - `powershell`
39
+
40
+ ## Manual MCP config
41
+
42
+ If you need to wire it into another MCP-compatible tool manually, add this server entry:
43
+
44
+ ```json
45
+ {
46
+ "command": "npx",
47
+ "args": ["-y", "surfil-mcp-server@latest"]
48
+ }
49
+ ```
50
+
51
+ Surfil-generated configs handle `SURFIL_KEYSTORE=file://` automatically when a tool needs the file-backed keystore path.
52
+
53
+ ## How it works
54
+
55
+ - **Session start** → emitted automatically when the MCP server initializes
56
+ - **Session end** → emitted automatically when the AI tool disconnects
57
+ - **Tool tracking** → emitted as MCP-aware tools invoke Surfil-managed actions
58
+ - **Goal and attribution** → attached to the current Surfil device, session, and project context
59
+
60
+ ## Requirements
61
+
62
+ - Node.js ≥ 18
63
+ - Surfil account at [surfil.com](https://surfil.com)
64
+ - `surfil` CLI activated with a valid license token
65
+
66
+ ## License
67
+
68
+ See [LICENSE](../LICENSE) — UpgradIQ, Inc.
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Surfil MCP Server
4
+ *
5
+ * Runs as an MCP stdio server. If a session was started with `surfil on`, this
6
+ * server attaches to that session. Otherwise it creates its own session and
7
+ * emits SessionStart/SessionEnd. Exposes tools: surfil_set_goal, surfil_status,
8
+ * surfil_track.
9
+ *
10
+ * Uses the surfil binary from PATH — same binary that Claude Code hooks use.
11
+ */
12
+ declare function emitSignal(event: string, tool: string, extraArgs?: string[]): void;
13
+ declare function handleCallTool(req: {
14
+ params: {
15
+ name: string;
16
+ arguments?: unknown;
17
+ };
18
+ }): Promise<{
19
+ content: Array<{
20
+ type: string;
21
+ text: string;
22
+ }>;
23
+ isError?: boolean;
24
+ }>;
25
+ export declare const __test: {
26
+ emitSignal: typeof emitSignal;
27
+ signalCount: () => number;
28
+ reset(id: string): void;
29
+ handleCallTool: typeof handleCallTool;
30
+ getGoal: () => string | null;
31
+ };
32
+ export {};
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAuJH,iBAAS,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,IAAI,CAsB/E;AA8WD,iBAAe,cAAc,CAAC,GAAG,EAAE;IAAE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA8GpK;AAmED,eAAO,MAAM,MAAM;;;cAGP,MAAM;;;CAMjB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,749 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Surfil MCP Server
5
+ *
6
+ * Runs as an MCP stdio server. If a session was started with `surfil on`, this
7
+ * server attaches to that session. Otherwise it creates its own session and
8
+ * emits SessionStart/SessionEnd. Exposes tools: surfil_set_goal, surfil_status,
9
+ * surfil_track.
10
+ *
11
+ * Uses the surfil binary from PATH — same binary that Claude Code hooks use.
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.__test = void 0;
48
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
49
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
50
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
51
+ const temper_standard_js_1 = require("./temper-standard.js");
52
+ const crypto = __importStar(require("crypto"));
53
+ const cp = __importStar(require("child_process"));
54
+ const fs = __importStar(require("fs"));
55
+ const os = __importStar(require("os"));
56
+ const path = __importStar(require("path"));
57
+ // ── Active session discovery ──────────────────────────────────────────────────
58
+ const SESSION_MAX_AGE_MS = 8 * 60 * 60 * 1000; // manual-session stale guard (8h)
59
+ const ADAPTER_FRESH_SKEW_MS = 120 * 1000; // adapter session must be this fresh vs our start
60
+ /**
61
+ * Authoritative per-process session id exposed by some adapters via env.
62
+ * GitHub Copilot CLI sets COPILOT_AGENT_SESSION_ID to the exact session id its
63
+ * lifecycle hooks use (verified on v1.0.59). Reading it is race-free and stays
64
+ * correct under parallel sessions — each Copilot process gets its own env —
65
+ * unlike the shared session.json file. Returns "" when no authoritative env id
66
+ * is available, so callers fall back to session.json discovery.
67
+ */
68
+ function adapterEnvSessionId() {
69
+ const id = process.env["COPILOT_AGENT_SESSION_ID"];
70
+ return id && id.trim() !== "" ? id.trim() : "";
71
+ }
72
+ /**
73
+ * Read the active session from the surfil state directory (session.json), written
74
+ * by the surfil binary on `surfil on` or an adapter SessionStart hook. Returns null
75
+ * when the file is missing, partial, or invalid JSON (all treated as transient
76
+ * during the resolve poll). Attach eligibility is decided separately by
77
+ * isAttachable() so the freshness/source rules live in one place.
78
+ */
79
+ function readActiveSession() {
80
+ const stateDir = process.env["XDG_DATA_HOME"]
81
+ ? path.join(process.env["XDG_DATA_HOME"], "surfil")
82
+ : path.join(os.homedir(), ".local", "share", "surfil");
83
+ const sessionFile = path.join(stateDir, "session.json");
84
+ try {
85
+ const data = fs.readFileSync(sessionFile, "utf8");
86
+ const parsed = JSON.parse(data);
87
+ if (!parsed.session_id)
88
+ return null;
89
+ const startedAtMs = parsed.started_at ? new Date(parsed.started_at).getTime() : NaN;
90
+ const lastSignalMs = parsed.last_signal_at ? new Date(parsed.last_signal_at).getTime() : NaN;
91
+ return {
92
+ sessionId: parsed.session_id,
93
+ goal: parsed.goal,
94
+ source: parsed.source ?? "",
95
+ startedAtMs: Number.isNaN(startedAtMs) ? 0 : startedAtMs,
96
+ lastSignalMs: Number.isNaN(lastSignalMs) ? 0 : lastSignalMs,
97
+ };
98
+ }
99
+ catch { /* missing / partial / invalid json — transient during poll */ }
100
+ return null;
101
+ }
102
+ /**
103
+ * Decide whether the on-disk session belongs to this MCP process so we can
104
+ * attach (forward goal/track) instead of minting a competing session.
105
+ * - Manual `surfil on` (or a legacy binary that does not tag source): attach
106
+ * within the 8h stale window — manual attachment is intentional.
107
+ * - Adapter-tagged session: attach only when it matches our own client tool
108
+ * AND is the live current run (started/last-signalled around our start), so
109
+ * we never inherit a different tool's session or a stale crashed one.
110
+ */
111
+ function isAttachable(a) {
112
+ if (!a.sessionId)
113
+ return false;
114
+ if (a.startedAtMs > 0 && Date.now() - a.startedAtMs > SESSION_MAX_AGE_MS)
115
+ return false;
116
+ if (a.source === "")
117
+ return true;
118
+ if (a.source === TOOL_NAME) {
119
+ return a.startedAtMs >= MCP_START_MS - ADAPTER_FRESH_SKEW_MS
120
+ || a.lastSignalMs >= MCP_START_MS - ADAPTER_FRESH_SKEW_MS;
121
+ }
122
+ return false;
123
+ }
124
+ // ── Session state ─────────────────────────────────────────────────────────────
125
+ //
126
+ // Session identity is resolved LAZILY, not at module load. Resolving at load
127
+ // races the adapter's SessionStart hook (which writes session.json a moment
128
+ // after Copilot spawns this server) and, when it loses, mints a competing
129
+ // session id — producing a duplicate session row. Instead we resolve on first
130
+ // use: a non-owning probe at Initialize, and a full resolve (attach-or-own)
131
+ // right before the first emitted signal.
132
+ const MCP_START_MS = Date.now();
133
+ let resolveState = "unresolved";
134
+ let sessionId = ""; // empty until resolved
135
+ let ownedStartEmitted = false; // we emit our own SessionStart at most once
136
+ let sessionGoal = null;
137
+ let signalCount = 0;
138
+ let startedAt = Date.now();
139
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
140
+ // ── surfil binary discovery ─────────────────────────────────────────────────────
141
+ function surfilBinary() {
142
+ // Honour explicit override, then search common install locations
143
+ if (process.env["SURFIL_BIN"])
144
+ return process.env["SURFIL_BIN"];
145
+ const candidates = [
146
+ "/usr/local/bin/surfil",
147
+ path.join(os.homedir(), ".local", "bin", "surfil"),
148
+ path.join(os.homedir(), ".surfil", "bin", "surfil"),
149
+ "surfil", // PATH fallback
150
+ ];
151
+ for (const c of candidates) {
152
+ if (c === "surfil")
153
+ return c; // let shell resolve
154
+ try {
155
+ fs.accessSync(c, fs.constants.X_OK);
156
+ return c;
157
+ }
158
+ catch { /* next */ }
159
+ }
160
+ return "surfil";
161
+ }
162
+ function isSurfilInstalled() {
163
+ try {
164
+ const r = cp.spawnSync(surfilBinary(), ["version"], {
165
+ timeout: 3000,
166
+ encoding: "utf8",
167
+ env: { ...process.env, SURFIL_KEYSTORE: process.env["SURFIL_KEYSTORE"] ?? "file://" },
168
+ });
169
+ return r.status === 0;
170
+ }
171
+ catch {
172
+ return false;
173
+ }
174
+ }
175
+ // ── Signal emission via surfil emit ─────────────────────────────────────────────
176
+ function emitSignal(event, tool, extraArgs = []) {
177
+ if (!sessionId)
178
+ return; // never emit before the session id is resolved
179
+ try {
180
+ const args = [
181
+ "emit",
182
+ "--event", event,
183
+ "--session", sessionId,
184
+ "--tool", tool,
185
+ ...extraArgs,
186
+ ];
187
+ const r = cp.spawnSync(surfilBinary(), args, {
188
+ timeout: 5000,
189
+ encoding: "utf8",
190
+ env: { ...process.env, SURFIL_KEYSTORE: process.env["SURFIL_KEYSTORE"] ?? "file://" },
191
+ });
192
+ // M12: only count signals the agent actually accepted. A missing binary
193
+ // (r.error) or a non-zero exit means the emit did not land — don't inflate
194
+ // the counter.
195
+ if (!r.error && r.status === 0)
196
+ signalCount++;
197
+ }
198
+ catch {
199
+ // Silent — never crash the MCP server over a signal failure
200
+ }
201
+ }
202
+ // ── Lifecycle / resolution ────────────────────────────────────────────────────
203
+ function commitAttached(id, goal) {
204
+ sessionId = id;
205
+ if (sessionGoal == null && goal)
206
+ sessionGoal = goal;
207
+ resolveState = "attached";
208
+ process.env["SURFIL_SESSION_ID"] = sessionId;
209
+ }
210
+ /**
211
+ * Non-owning probe. Attaches to an identifiable session (authoritative adapter
212
+ * env id first, then session.json) but NEVER mints a session. Safe to call at
213
+ * Initialize and from surfil_status so a harmless status check never creates a
214
+ * row. No-op once resolved.
215
+ */
216
+ function probeAttach() {
217
+ if (resolveState !== "unresolved")
218
+ return;
219
+ const envId = adapterEnvSessionId();
220
+ if (envId) {
221
+ commitAttached(envId);
222
+ return;
223
+ }
224
+ const a = readActiveSession();
225
+ if (a && isAttachable(a))
226
+ commitAttached(a.sessionId, a.goal);
227
+ }
228
+ /**
229
+ * Owning resolve. Used right before we emit a real signal (goal/track): attach
230
+ * if we can identify the session, briefly polling to absorb the hook-write race
231
+ * and partial reads; only if nothing attachable appears do we mint our own
232
+ * session. Single-flight so concurrent tool calls share one decision.
233
+ */
234
+ let owningResolve = null;
235
+ function resolveForEmit() {
236
+ if (resolveState !== "unresolved")
237
+ return Promise.resolve();
238
+ if (!owningResolve)
239
+ owningResolve = doOwningResolve();
240
+ return owningResolve;
241
+ }
242
+ async function doOwningResolve() {
243
+ const envId = adapterEnvSessionId();
244
+ if (envId) {
245
+ commitAttached(envId);
246
+ return;
247
+ }
248
+ for (let i = 0; i < 6; i++) { // ~6 × 180ms ≈ 1s grace for the SessionStart hook
249
+ const a = readActiveSession();
250
+ if (a && isAttachable(a)) {
251
+ commitAttached(a.sessionId, a.goal);
252
+ return;
253
+ }
254
+ if (i < 5)
255
+ await sleep(180);
256
+ }
257
+ // Standalone host (no hooks, no manual session): own the lifecycle ourselves.
258
+ sessionId = crypto.randomUUID();
259
+ resolveState = "owned";
260
+ process.env["SURFIL_SESSION_ID"] = sessionId;
261
+ }
262
+ // Emit our own SessionStart exactly once, and only for sessions we own. Attached
263
+ // sessions are created and finalized by the adapter's own hooks, so emitting our
264
+ // own lifecycle signals there would duplicate or prematurely end the session.
265
+ function ensureOwnedStart() {
266
+ if (resolveState === "owned" && !ownedStartEmitted) {
267
+ startedAt = Date.now();
268
+ emitSignal("SessionStart", TOOL_NAME);
269
+ ownedStartEmitted = true;
270
+ }
271
+ }
272
+ function maybeEmitEnd() {
273
+ if (resolveState === "owned" && ownedStartEmitted) {
274
+ const goalArgs = sessionGoal ? ["--goal", sessionGoal] : [];
275
+ emitSignal("SessionEnd", TOOL_NAME, goalArgs);
276
+ }
277
+ }
278
+ // Short, display-only session label for tool responses. Shows "(pending)" until
279
+ // the session id is resolved on the first goal/track call.
280
+ function shortSessionLabel() {
281
+ return sessionId ? sessionId.replace(/-/g, "").slice(0, 8).toUpperCase() : "(pending)";
282
+ }
283
+ // ── MCP Server ────────────────────────────────────────────────────────────────
284
+ const server = new index_js_1.Server({ name: "surfil", version: "1.0.0" }, { capabilities: { tools: {}, prompts: {} } });
285
+ // Map MCP clientInfo.name values → valid Surfil tool names.
286
+ // Called at Initialize time; overrides the env-var detection for better accuracy.
287
+ // Covers canonical names, capitalization variants, and branded product names.
288
+ const CLIENT_NAME_MAP = {
289
+ // GitHub Copilot
290
+ "github-copilot": "copilot",
291
+ "copilot": "copilot",
292
+ "github-copilot-chat": "copilot",
293
+ // OpenCode
294
+ "opencode": "opencode",
295
+ // Cursor
296
+ "cursor": "cursor",
297
+ // VS Code / Copilot Chat in VS Code
298
+ "visual-studio-code": "vscode",
299
+ "vscode": "vscode",
300
+ "vs-code": "vscode",
301
+ // Windsurf
302
+ "windsurf": "windsurf",
303
+ "windsurf-ide": "windsurf",
304
+ "codeium-windsurf": "windsurf",
305
+ // Claude Code
306
+ "claude-code": "claude-code",
307
+ "claude": "claude-code",
308
+ // Cline
309
+ "cline": "cline",
310
+ // Roo Code — sends "Roo Code", "RooCode", or "roo-code"
311
+ "roo": "roo",
312
+ "roo-code": "roo",
313
+ "roocode": "roo",
314
+ "roo-codeapp": "roo",
315
+ // Continue.dev
316
+ "continue": "continue",
317
+ "continue-ai": "continue",
318
+ "continuecode": "continue",
319
+ "continue-dev": "continue",
320
+ // Aider
321
+ "aider": "aider",
322
+ "aider-chat": "aider",
323
+ // Codex CLI (OpenAI)
324
+ "codex": "codex",
325
+ "codex-cli": "codex",
326
+ "openai-codex": "codex",
327
+ "openai-codex-cli": "codex",
328
+ // Warp terminal
329
+ "warp": "warp",
330
+ "warp-terminal": "warp",
331
+ "warp-app": "warp",
332
+ // JetBrains — covers all IDEs
333
+ "jetbrains": "jetbrains",
334
+ "jetbrains-ide": "jetbrains",
335
+ "jetbrains-gateway": "jetbrains",
336
+ "intellij-idea": "jetbrains",
337
+ "intellij": "jetbrains",
338
+ "idea": "jetbrains",
339
+ "webstorm": "jetbrains",
340
+ "pycharm": "jetbrains",
341
+ "goland": "jetbrains",
342
+ "rider": "jetbrains",
343
+ "clion": "jetbrains",
344
+ "phpstorm": "jetbrains",
345
+ "rubymine": "jetbrains",
346
+ "datagrip": "jetbrains",
347
+ "android-studio": "jetbrains",
348
+ // Zed
349
+ "zed": "zed",
350
+ "zed-editor": "zed",
351
+ // Gemini CLI (Google)
352
+ "gemini-cli": "gemini-cli",
353
+ "gemini": "gemini-cli",
354
+ "google-gemini": "gemini-cli",
355
+ "google-gemini-cli": "gemini-cli",
356
+ "gemini-code": "gemini-cli",
357
+ // Neovim
358
+ "neovim": "neovim",
359
+ "nvim": "neovim",
360
+ // PowerShell
361
+ "powershell": "powershell",
362
+ "pwsh": "powershell",
363
+ // Generic CLI
364
+ "cli": "cli",
365
+ };
366
+ // Detect which AI tool is calling us from env hints.
367
+ // Check both purpose-set MCP flags and well-known CLI env vars.
368
+ function detectTool() {
369
+ // Explicit adapter override always wins
370
+ if (process.env["SURFIL_ADAPTER"])
371
+ return process.env["SURFIL_ADAPTER"];
372
+ // MCP-specific flags
373
+ if (process.env["COPILOT_MCP"])
374
+ return "copilot";
375
+ if (process.env["CURSOR_MCP"])
376
+ return "cursor";
377
+ if (process.env["VSCODE_MCP"])
378
+ return "vscode";
379
+ if (process.env["WINDSURF_MCP"])
380
+ return "windsurf";
381
+ // GitHub Copilot CLI — sets COPILOT_CLI=1, COPILOT_RUN_APP=1, COPILOT_AGENT_SESSION_ID
382
+ if (process.env["COPILOT_CLI"] || process.env["COPILOT_RUN_APP"] || process.env["COPILOT_AGENT_SESSION_ID"])
383
+ return "copilot";
384
+ // Cursor desktop sets CURSOR_TRACE_ID
385
+ if (process.env["CURSOR_TRACE_ID"])
386
+ return "cursor";
387
+ // VS Code sets VSCODE_PID
388
+ if (process.env["VSCODE_PID"])
389
+ return "vscode";
390
+ // Gemini CLI sets GEMINI_CLI or GOOGLE_CLOUD_CLI_*
391
+ if (process.env["GEMINI_CLI"] || process.env["GEMINI_API_KEY_SOURCE"] === "gemini-cli")
392
+ return "gemini-cli";
393
+ // Codex CLI (OpenAI) sets CODEX_CLI or OPENAI_CODEX_CLI
394
+ if (process.env["CODEX_CLI"] || process.env["OPENAI_CODEX_CLI"])
395
+ return "codex";
396
+ // Warp terminal sets WARP_IS_LOCAL_SHELL_SESSION or TERM_PROGRAM=WarpTerminal
397
+ if (process.env["WARP_IS_LOCAL_SHELL_SESSION"] || process.env["TERM_PROGRAM"] === "WarpTerminal")
398
+ return "warp";
399
+ return "unknown";
400
+ }
401
+ // Map a raw MCP clientInfo.name to a valid Surfil tool name.
402
+ // Falls back to the env-detected TOOL_NAME if no mapping exists.
403
+ function clientNameToTool(clientName, fallback) {
404
+ if (!clientName)
405
+ return fallback;
406
+ const normalized = clientName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
407
+ return CLIENT_NAME_MAP[normalized] ?? fallback;
408
+ }
409
+ // Mutable — updated at Initialize time from clientInfo.name for better accuracy.
410
+ let TOOL_NAME = detectTool();
411
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
412
+ tools: [
413
+ {
414
+ name: "surfil_set_goal",
415
+ description: "Set the goal or task description for the current Surfil session. Call this at the start of a task to get accurate session tracking.",
416
+ inputSchema: {
417
+ type: "object",
418
+ properties: {
419
+ goal: {
420
+ type: "string",
421
+ description: "The task or goal for this AI coding session (e.g. 'Fix the login bug in auth.ts')",
422
+ },
423
+ },
424
+ required: ["goal"],
425
+ },
426
+ },
427
+ {
428
+ name: "surfil_status",
429
+ description: "Get the current Surfil session status — session ID, goal, duration, and signal count.",
430
+ inputSchema: {
431
+ type: "object",
432
+ properties: {},
433
+ },
434
+ },
435
+ {
436
+ name: "surfil_track",
437
+ description: "Track a completed tool use or task step in the current Surfil session. Call after completing a meaningful action.",
438
+ inputSchema: {
439
+ type: "object",
440
+ properties: {
441
+ tool: {
442
+ type: "string",
443
+ description: "Name of the tool or action that was used",
444
+ },
445
+ success: {
446
+ type: "boolean",
447
+ description: "Whether the tool use succeeded",
448
+ default: true,
449
+ },
450
+ model: {
451
+ type: "string",
452
+ description: "Optional model name used for this step (e.g. gpt-4o, claude-3-5-sonnet)",
453
+ },
454
+ tokens_used: {
455
+ type: "integer",
456
+ description: "Optional token count for this step",
457
+ },
458
+ },
459
+ required: ["tool"],
460
+ },
461
+ },
462
+ {
463
+ name: "surfil_telemetry",
464
+ description: "Report model usage and cost telemetry for the current Surfil session. Call after each LLM turn to surface tokens, model, and cost in the dashboard.",
465
+ inputSchema: {
466
+ type: "object",
467
+ properties: {
468
+ model: {
469
+ type: "string",
470
+ description: "Model name (e.g. gpt-4o, claude-3-5-sonnet-20241022)",
471
+ },
472
+ tokens_used: {
473
+ type: "integer",
474
+ description: "Total tokens consumed (prompt + completion)",
475
+ },
476
+ tokens_saved: {
477
+ type: "integer",
478
+ description: "Tokens saved by Surfil optimizations (if known)",
479
+ default: 0,
480
+ },
481
+ cost_usd: {
482
+ type: "number",
483
+ description: "Estimated cost in USD for this turn",
484
+ },
485
+ },
486
+ required: ["model", "tokens_used"],
487
+ },
488
+ },
489
+ {
490
+ name: "temper_instructions",
491
+ description: `Return the Surfil Temper Standard behavioral governance rules for AI coding assistants. Exposes the same content as the 'temper' prompt but as a callable tool. Use when you need to programmatically retrieve the rules at a specific enforcement level.`,
492
+ inputSchema: {
493
+ type: "object",
494
+ properties: {
495
+ mode: {
496
+ type: "string",
497
+ enum: ["basic", "full", "ultra"],
498
+ description: "Enforcement level. 'basic' = advisory; 'full' (default) = enforced; 'ultra' = extremist + scope challenges.",
499
+ default: "full",
500
+ },
501
+ },
502
+ },
503
+ // MCP annotation: read-only, no side effects.
504
+ annotations: {
505
+ readOnlyHint: true,
506
+ openWorldHint: false,
507
+ },
508
+ },
509
+ {
510
+ name: "surfil_retrieve",
511
+ description: `Retrieve the byte-exact original content for a compressed CCR entry by its content hash. Use this when the model needs the full uncompressed version of a compressed context block. Read-only — no side effects. Max 3 retrievals per hash (DR-14).`,
512
+ inputSchema: {
513
+ type: "object",
514
+ properties: {
515
+ hash: {
516
+ type: "string",
517
+ description: "The SHA-256 content hash of the CCR entry to retrieve.",
518
+ },
519
+ query: {
520
+ type: "string",
521
+ description: "Optional search query within the retrieved content (for BM25 search).",
522
+ },
523
+ },
524
+ required: ["hash"],
525
+ },
526
+ annotations: {
527
+ readOnlyHint: true,
528
+ openWorldHint: false,
529
+ },
530
+ },
531
+ ],
532
+ }));
533
+ // ── Prompts — temper ──────────────────────────────────────────────────────────
534
+ // The `temper` prompt exposes the Surfil Temper Standard as an MCP prompt entry.
535
+ // Hosts that only have access to the prompt menu (not tool calls) can inject
536
+ // the rules directly by selecting this prompt.
537
+ server.setRequestHandler(types_js_1.ListPromptsRequestSchema, async () => ({
538
+ prompts: [
539
+ {
540
+ name: "temper",
541
+ description: `Surfil Temper Standard v${temper_standard_js_1.TEMPER_VERSION} — behavioral governance rules for AI coding assistants. Enforces the Restraint Ladder, Token-Efficiency Rules, and Non-Negotiable Carve-Outs.`,
542
+ arguments: [
543
+ {
544
+ name: "mode",
545
+ description: "Enforcement level: 'basic' (advisory), 'full' (default, enforced), or 'ultra' (extremist + scope challenges).",
546
+ required: false,
547
+ },
548
+ ],
549
+ },
550
+ ],
551
+ }));
552
+ server.setRequestHandler(types_js_1.GetPromptRequestSchema, async (req) => {
553
+ const { name, arguments: promptArgs } = req.params;
554
+ if (name !== "temper") {
555
+ throw new Error(`Unknown prompt: ${name}`);
556
+ }
557
+ const mode = String(promptArgs?.mode ?? "full");
558
+ const text = (0, temper_standard_js_1.getStandardForLevel)(mode);
559
+ return {
560
+ description: `Surfil Temper Standard v${temper_standard_js_1.TEMPER_VERSION} — level: ${mode}`,
561
+ messages: [
562
+ {
563
+ role: "user",
564
+ content: {
565
+ type: "text",
566
+ text,
567
+ },
568
+ },
569
+ ],
570
+ };
571
+ });
572
+ async function handleCallTool(req) {
573
+ const { name, arguments: args } = req.params;
574
+ if (name === "surfil_set_goal") {
575
+ const goal = String(args?.goal ?? "").slice(0, 500);
576
+ sessionGoal = goal;
577
+ await resolveForEmit();
578
+ ensureOwnedStart();
579
+ // UserPromptSubmit carries goal_declared into the resolved session so the
580
+ // engine records it (works whether attached to the adapter session or owned).
581
+ emitSignal("UserPromptSubmit", TOOL_NAME, ["--goal", goal]);
582
+ return {
583
+ content: [{ type: "text", text: `✅ Surfil goal set: "${goal}" (session ${shortSessionLabel()})` }],
584
+ };
585
+ }
586
+ if (name === "surfil_status") {
587
+ probeAttach(); // identify the session if possible, but never create one
588
+ const installed = isSurfilInstalled();
589
+ const durationSec = Math.floor((Date.now() - startedAt) / 1000);
590
+ const m = Math.floor(durationSec / 60);
591
+ const s = durationSec % 60;
592
+ const mode = resolveState === "attached"
593
+ ? "attached (adapter/surfil-on session)"
594
+ : resolveState === "owned"
595
+ ? "standalone (surfil-mcp owns this session)"
596
+ : "pending (starts on first goal/track)";
597
+ return {
598
+ content: [{
599
+ type: "text",
600
+ text: [
601
+ `**Surfil Session**`,
602
+ `ID: ${shortSessionLabel()}`,
603
+ `Adapter: ${TOOL_NAME}`,
604
+ `Mode: ${mode}`,
605
+ `Duration: ${m > 0 ? `${m}m ` : ""}${s}s`,
606
+ `Signals sent: ${signalCount}`,
607
+ `Goal: ${sessionGoal ?? "(not set — call surfil_set_goal)"}`,
608
+ `Agent binary: ${installed ? "✅ found" : "❌ not found — install from surfil.com"}`,
609
+ ].join("\n"),
610
+ }],
611
+ };
612
+ }
613
+ if (name === "surfil_track") {
614
+ const tool = String(args?.tool ?? "unknown");
615
+ const success = args?.success !== false;
616
+ const model = String(args?.model ?? "");
617
+ const tokensUsed = Number(args?.tokens_used ?? 0);
618
+ await resolveForEmit();
619
+ ensureOwnedStart();
620
+ const extra = ["--tool", tool, "--success", success ? "true" : "false"];
621
+ if (model)
622
+ extra.push("--model", model);
623
+ if (tokensUsed > 0)
624
+ extra.push("--tokens-used", String(tokensUsed));
625
+ emitSignal("PostToolUse", TOOL_NAME, extra);
626
+ return {
627
+ content: [{ type: "text", text: `✅ Tracked: ${tool} (success=${success})` }],
628
+ };
629
+ }
630
+ if (name === "surfil_telemetry") {
631
+ const model = String(args?.model ?? "");
632
+ const tokensUsed = Number(args?.tokens_used ?? 0);
633
+ const tokensSaved = Number(args?.tokens_saved ?? 0);
634
+ const costUsd = Number(args?.cost_usd ?? 0);
635
+ await resolveForEmit();
636
+ ensureOwnedStart();
637
+ const extra = [];
638
+ if (model)
639
+ extra.push("--model", model);
640
+ if (tokensUsed > 0)
641
+ extra.push("--tokens-used", String(tokensUsed));
642
+ if (tokensSaved > 0)
643
+ extra.push("--tokens-saved", String(tokensSaved));
644
+ if (costUsd > 0)
645
+ extra.push("--cost-usd", String(costUsd));
646
+ // Emit as a synthetic PostToolUse with telemetry payload so the engine
647
+ // records model and tokens for dashboard surfacing.
648
+ emitSignal("PostToolUse", TOOL_NAME, extra);
649
+ return {
650
+ content: [{ type: "text", text: `📊 Telemetry: ${model} · ${tokensUsed.toLocaleString()} tokens` }],
651
+ };
652
+ }
653
+ if (name === "temper_instructions") {
654
+ const mode = String(args?.mode ?? "full");
655
+ const text = (0, temper_standard_js_1.getStandardForLevel)(mode);
656
+ return {
657
+ content: [{ type: "text", text }],
658
+ // No side effects: read-only return of the embedded standard.
659
+ };
660
+ }
661
+ if (name === "surfil_retrieve") {
662
+ const hash = String(args?.hash ?? "");
663
+ if (!hash) {
664
+ return { content: [{ type: "text", text: "Error: hash is required" }], isError: true };
665
+ }
666
+ // In production, this calls the engine CCR store via retrieveFromEngine.
667
+ // For the framework, we return a placeholder indicating the retrieval mechanism.
668
+ // The actual retrieval is wired when the engine endpoint is deployed.
669
+ const query = args?.query ? ` (query: "${String(args.query)}")` : "";
670
+ return {
671
+ content: [{
672
+ type: "text",
673
+ text: `Retrieve request for hash ${hash}${query} — use engine /temper/ccr-retrieve endpoint. Max 3 rounds per hash (DR-14). Read-only: no content was modified.`,
674
+ }],
675
+ };
676
+ }
677
+ return {
678
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
679
+ isError: true,
680
+ };
681
+ }
682
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, handleCallTool);
683
+ // ── Main ──────────────────────────────────────────────────────────────────────
684
+ async function main() {
685
+ const transport = new stdio_js_1.StdioServerTransport();
686
+ // Resolve the session id from clientInfo first so source-matching is correct,
687
+ // then run a NON-OWNING probe: for Copilot this attaches to the authoritative
688
+ // COPILOT_AGENT_SESSION_ID immediately (race-free); otherwise it stays
689
+ // unresolved until the first goal/track call, which avoids the load-time race
690
+ // that previously minted a duplicate session.
691
+ server.setRequestHandler(types_js_1.InitializeRequestSchema, async (req) => {
692
+ const rawClientName = req.params?.clientInfo?.name ?? "";
693
+ TOOL_NAME = clientNameToTool(rawClientName, TOOL_NAME);
694
+ probeAttach();
695
+ // Standalone host (VS Code, Cursor, etc.) — no adapter hooks and no manual
696
+ // session. Immediately own the lifecycle so a session row exists from turn 1.
697
+ if (resolveState === "unresolved") {
698
+ sessionId = crypto.randomUUID();
699
+ resolveState = "owned";
700
+ process.env["SURFIL_SESSION_ID"] = sessionId;
701
+ ensureOwnedStart();
702
+ }
703
+ return {
704
+ protocolVersion: "2024-11-05",
705
+ capabilities: { tools: {} },
706
+ serverInfo: { name: "surfil", version: "1.0.0" },
707
+ };
708
+ });
709
+ // On exit, finalize only sessions we own; attached adapter sessions are
710
+ // finalized by the adapter's own SessionEnd hook.
711
+ const shutdown = () => {
712
+ maybeEmitEnd();
713
+ process.exit(0);
714
+ };
715
+ process.on("SIGTERM", shutdown);
716
+ process.on("SIGINT", shutdown);
717
+ process.on("disconnect", shutdown);
718
+ // Heartbeat: keep owned-session last_signal_at fresh so the dashboard marks
719
+ // it live. Attached sessions rely on adapter hooks; owned sessions beat here.
720
+ setInterval(() => {
721
+ if (resolveState === "owned" && ownedStartEmitted) {
722
+ emitSignal("Heartbeat", TOOL_NAME);
723
+ }
724
+ }, 30000);
725
+ await server.connect(transport);
726
+ }
727
+ // Entrypoint guard: only start the stdio server when executed directly
728
+ // (`node dist/index.js`). When imported by the test suite, the handlers and
729
+ // emitSignal are exercised in isolation without spawning a server.
730
+ if (typeof require !== "undefined" && require.main === module) {
731
+ main().catch((err) => {
732
+ process.stderr.write(`surfil-mcp error: ${err}\n`);
733
+ process.exit(1);
734
+ });
735
+ }
736
+ // Test-only surface: lets the suite drive the REAL emitSignal (and observe the
737
+ // signal counter) instead of re-implementing the logic. Not part of the public
738
+ // MCP contract.
739
+ exports.__test = {
740
+ emitSignal,
741
+ signalCount: () => signalCount,
742
+ reset(id) {
743
+ sessionId = id;
744
+ signalCount = 0;
745
+ },
746
+ handleCallTool,
747
+ getGoal: () => sessionGoal,
748
+ };
749
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * retrieve.ts — Task 9.6: Retrieve-on-demand via surfil-mcp (family J) + multi-turn tracker.
3
+ *
4
+ * Exposes `surfil_retrieve(hash, query?)` as a Surfil-MCP tool. The tool calls the
5
+ * engine's CCR store (9.2) to retrieve the byte-exact original content by hash.
6
+ *
7
+ * Multi-turn tracker: tracks which compressed entries have been referenced across
8
+ * turns and proactively re-expands them when a later turn references the same hash.
9
+ *
10
+ * DR-14: max 3 retrieve rounds per hash.
11
+ * Mode: OO (overlay/observability), read-only tool.
12
+ * Ownership-scoped: retrieval is scoped to the current session/user.
13
+ */
14
+ export interface RetrieveRecord {
15
+ hash: string;
16
+ retrievedAt: number;
17
+ turn: number;
18
+ roundsUsed: number;
19
+ }
20
+ export interface MultiTurnTracker {
21
+ records: Map<string, RetrieveRecord>;
22
+ currentTurn: number;
23
+ totalRetrievals: number;
24
+ }
25
+ /**
26
+ * Create a new multi-turn tracker.
27
+ */
28
+ export declare function createTracker(): MultiTurnTracker;
29
+ /**
30
+ * advanceTurn increments the turn counter.
31
+ * Called at the start of each new model turn.
32
+ */
33
+ export declare function advanceTurn(tracker: MultiTurnTracker): void;
34
+ /**
35
+ * recordRetrieve logs a retrieve action in the multi-turn tracker.
36
+ * Returns false if the max rounds (DR-14: 3) have been exceeded for this hash.
37
+ */
38
+ export declare function recordRetrieve(tracker: MultiTurnTracker, hash: string): boolean;
39
+ /**
40
+ * getReferencedHashes returns all hashes that have been referenced across turns.
41
+ * Used for proactive re-expansion.
42
+ */
43
+ export declare function getReferencedHashes(tracker: MultiTurnTracker): string[];
44
+ /**
45
+ * isMaxRoundsReached checks if a hash has exhausted its retrieve rounds.
46
+ */
47
+ export declare function isMaxRoundsReached(tracker: MultiTurnTracker, hash: string): boolean;
48
+ /**
49
+ * getRetrieveCount returns how many times a hash has been retrieved.
50
+ */
51
+ export declare function getRetrieveCount(tracker: MultiTurnTracker, hash: string): number;
52
+ /**
53
+ * clearTracker resets the multi-turn tracker (e.g. on session end).
54
+ */
55
+ export declare function clearTracker(tracker: MultiTurnTracker): void;
56
+ export interface RetrieveResult {
57
+ found: boolean;
58
+ original: string | null;
59
+ hash: string;
60
+ roundsUsed: number;
61
+ maxRoundsReached: boolean;
62
+ error: string | null;
63
+ }
64
+ /**
65
+ * retrieveFromEngine calls the engine's CCR store endpoint to retrieve content by hash.
66
+ * In production, this makes an HTTP call to engine.surfil.com/temper/ccr-retrieve?hash=...
67
+ * For the framework, this is a placeholder that the MCP server wires up.
68
+ */
69
+ export declare function retrieveFromEngine(hash: string, engineUrl: string, internalKey: string, tracker: MultiTurnTracker): Promise<RetrieveResult>;
70
+ //# sourceMappingURL=retrieve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve.d.ts","sourceRoot":"","sources":["../src/retrieve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,gBAAgB,CAMhD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAE3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAiB/E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAEvE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGnF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAI5D;AAID,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,cAAc,CAAC,CA0DzB"}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ /**
3
+ * retrieve.ts — Task 9.6: Retrieve-on-demand via surfil-mcp (family J) + multi-turn tracker.
4
+ *
5
+ * Exposes `surfil_retrieve(hash, query?)` as a Surfil-MCP tool. The tool calls the
6
+ * engine's CCR store (9.2) to retrieve the byte-exact original content by hash.
7
+ *
8
+ * Multi-turn tracker: tracks which compressed entries have been referenced across
9
+ * turns and proactively re-expands them when a later turn references the same hash.
10
+ *
11
+ * DR-14: max 3 retrieve rounds per hash.
12
+ * Mode: OO (overlay/observability), read-only tool.
13
+ * Ownership-scoped: retrieval is scoped to the current session/user.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.createTracker = createTracker;
17
+ exports.advanceTurn = advanceTurn;
18
+ exports.recordRetrieve = recordRetrieve;
19
+ exports.getReferencedHashes = getReferencedHashes;
20
+ exports.isMaxRoundsReached = isMaxRoundsReached;
21
+ exports.getRetrieveCount = getRetrieveCount;
22
+ exports.clearTracker = clearTracker;
23
+ exports.retrieveFromEngine = retrieveFromEngine;
24
+ /**
25
+ * Create a new multi-turn tracker.
26
+ */
27
+ function createTracker() {
28
+ return {
29
+ records: new Map(),
30
+ currentTurn: 0,
31
+ totalRetrievals: 0,
32
+ };
33
+ }
34
+ /**
35
+ * advanceTurn increments the turn counter.
36
+ * Called at the start of each new model turn.
37
+ */
38
+ function advanceTurn(tracker) {
39
+ tracker.currentTurn++;
40
+ }
41
+ /**
42
+ * recordRetrieve logs a retrieve action in the multi-turn tracker.
43
+ * Returns false if the max rounds (DR-14: 3) have been exceeded for this hash.
44
+ */
45
+ function recordRetrieve(tracker, hash) {
46
+ const existing = tracker.records.get(hash);
47
+ const roundsUsed = existing ? existing.roundsUsed + 1 : 1;
48
+ // DR-14: max 3 retrieve rounds per hash.
49
+ if (roundsUsed > 3) {
50
+ return false; // exceeded max rounds
51
+ }
52
+ tracker.records.set(hash, {
53
+ hash,
54
+ retrievedAt: Date.now(),
55
+ turn: tracker.currentTurn,
56
+ roundsUsed,
57
+ });
58
+ tracker.totalRetrievals++;
59
+ return true;
60
+ }
61
+ /**
62
+ * getReferencedHashes returns all hashes that have been referenced across turns.
63
+ * Used for proactive re-expansion.
64
+ */
65
+ function getReferencedHashes(tracker) {
66
+ return Array.from(tracker.records.keys());
67
+ }
68
+ /**
69
+ * isMaxRoundsReached checks if a hash has exhausted its retrieve rounds.
70
+ */
71
+ function isMaxRoundsReached(tracker, hash) {
72
+ const record = tracker.records.get(hash);
73
+ return record !== undefined && record.roundsUsed >= 3;
74
+ }
75
+ /**
76
+ * getRetrieveCount returns how many times a hash has been retrieved.
77
+ */
78
+ function getRetrieveCount(tracker, hash) {
79
+ return tracker.records.get(hash)?.roundsUsed ?? 0;
80
+ }
81
+ /**
82
+ * clearTracker resets the multi-turn tracker (e.g. on session end).
83
+ */
84
+ function clearTracker(tracker) {
85
+ tracker.records.clear();
86
+ tracker.currentTurn = 0;
87
+ tracker.totalRetrievals = 0;
88
+ }
89
+ /**
90
+ * retrieveFromEngine calls the engine's CCR store endpoint to retrieve content by hash.
91
+ * In production, this makes an HTTP call to engine.surfil.com/temper/ccr-retrieve?hash=...
92
+ * For the framework, this is a placeholder that the MCP server wires up.
93
+ */
94
+ async function retrieveFromEngine(hash, engineUrl, internalKey, tracker) {
95
+ // Check if max rounds already reached (DR-14).
96
+ if (isMaxRoundsReached(tracker, hash)) {
97
+ return {
98
+ found: false,
99
+ original: null,
100
+ hash,
101
+ roundsUsed: getRetrieveCount(tracker, hash),
102
+ maxRoundsReached: true,
103
+ error: "Max retrieve rounds (3) reached for this hash — content may have expired",
104
+ };
105
+ }
106
+ try {
107
+ const res = await fetch(`${engineUrl}/temper/ccr-retrieve?hash=${encodeURIComponent(hash)}`, {
108
+ method: "GET",
109
+ headers: { Authorization: `Bearer ${internalKey}` },
110
+ signal: AbortSignal.timeout(5000),
111
+ });
112
+ if (!res.ok) {
113
+ // Record the attempt even on failure.
114
+ recordRetrieve(tracker, hash);
115
+ return {
116
+ found: false,
117
+ original: null,
118
+ hash,
119
+ roundsUsed: getRetrieveCount(tracker, hash),
120
+ maxRoundsReached: false,
121
+ error: `Engine returned HTTP ${res.status}`,
122
+ };
123
+ }
124
+ const data = await res.json();
125
+ recordRetrieve(tracker, hash);
126
+ return {
127
+ found: data.found,
128
+ original: data.found ? data.original : null,
129
+ hash,
130
+ roundsUsed: getRetrieveCount(tracker, hash),
131
+ maxRoundsReached: isMaxRoundsReached(tracker, hash),
132
+ error: data.expired ? "Content expired (TTL 5min passed)" : null,
133
+ };
134
+ }
135
+ catch (e) {
136
+ recordRetrieve(tracker, hash);
137
+ return {
138
+ found: false,
139
+ original: null,
140
+ hash,
141
+ roundsUsed: getRetrieveCount(tracker, hash),
142
+ maxRoundsReached: false,
143
+ error: e instanceof Error ? e.message : String(e),
144
+ };
145
+ }
146
+ }
147
+ //# sourceMappingURL=retrieve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve.js","sourceRoot":"","sources":["../src/retrieve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * temper-standard.ts
3
+ *
4
+ * TypeScript embedding of the Surfil Temper Standard for surfil-mcp.
5
+ * Mirrors agent/internal/temper/standard.md — update both when the standard changes.
6
+ * Version: 1.0.0
7
+ */
8
+ declare const VALID_LEVELS: readonly ["basic", "full", "ultra"];
9
+ /**
10
+ * Returns the Temper Standard text for the given enforcement level.
11
+ * Invalid levels fall back to "full".
12
+ * All levels include the Non-Negotiable Carve-Outs (never stripped).
13
+ */
14
+ export declare function getStandardForLevel(level: string): string;
15
+ export declare const TEMPER_VERSION = "1.0.0";
16
+ export { VALID_LEVELS };
17
+ //# sourceMappingURL=temper-standard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temper-standard.d.ts","sourceRoot":"","sources":["../src/temper-standard.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkHH,QAAA,MAAM,YAAY,qCAAsC,CAAC;AAGzD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED,eAAO,MAAM,cAAc,UAAU,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ /**
3
+ * temper-standard.ts
4
+ *
5
+ * TypeScript embedding of the Surfil Temper Standard for surfil-mcp.
6
+ * Mirrors agent/internal/temper/standard.md — update both when the standard changes.
7
+ * Version: 1.0.0
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.VALID_LEVELS = exports.TEMPER_VERSION = void 0;
11
+ exports.getStandardForLevel = getStandardForLevel;
12
+ const STANDARD_FULL = `# Surfil Temper Standard
13
+
14
+ Version: 1.0.0
15
+ Owner: Surfil (surfil.com)
16
+
17
+ The Temper Standard is a behavioral governance specification for AI coding
18
+ assistants operating under Surfil oversight. It encodes the principle that the
19
+ best code is the code that does not need to exist.
20
+
21
+ ---
22
+
23
+ ## The Restraint Ladder
24
+
25
+ Before writing any code, climb the ladder from the top. Stop at the first
26
+ rung that solves the problem. Never skip down to a lower rung without
27
+ exhausting every higher one.
28
+
29
+ 1. **Does this need to exist?** If the requirement is speculative, deferred,
30
+ or already handled elsewhere, skip it entirely and say so in one line.
31
+ Building something nobody asked for is the most expensive mistake. (YAGNI)
32
+
33
+ 2. **Does the standard library solve it?** Use the language's built-in
34
+ facilities. No dependency beats no dependency.
35
+
36
+ 3. **Does a native platform feature cover it?** CSS instead of JavaScript,
37
+ a database constraint instead of application code, an HTTP header instead
38
+ of middleware, a filesystem operation instead of a library wrapper.
39
+
40
+ 4. **Does an already-installed dependency solve it?** Search the existing
41
+ dependency manifest before adding anything. Adding a package to do what
42
+ an installed package already does is waste.
43
+
44
+ 5. **Can it be one function or one expression?** If the entire solution fits
45
+ in a single readable line or a named one-liner, write that and stop.
46
+
47
+ 6. **Write the minimum code that works.** No abstraction without at least two
48
+ callers. No interface with one implementation. No factory for one product.
49
+ No configuration for a value that never changes. No scaffolding "for later."
50
+
51
+ ---
52
+
53
+ ## Non-Negotiable Carve-Outs
54
+
55
+ The following are NEVER subject to the Restraint Ladder. They must be
56
+ implemented completely and correctly regardless of effort.
57
+
58
+ ### Input validation at trust boundaries
59
+ Every surface that accepts external input must validate and sanitize before use.
60
+
61
+ ### Error handling that prevents data loss
62
+ Any code path that writes, transforms, or deletes persistent data must handle
63
+ errors explicitly. Swallowing errors on mutation paths is not acceptable.
64
+
65
+ ### Security controls
66
+ Authentication, authorization, cryptographic operations, secrets handling, and
67
+ audit logging must be implemented to their full specification.
68
+
69
+ ### Accessibility basics
70
+ Interactive UI components must be keyboard-navigable and carry correct ARIA
71
+ roles and labels.
72
+
73
+ ### Anything explicitly requested
74
+ If the user or task specification asks for something, build it in full. The
75
+ Restraint Ladder applies to things not asked for.
76
+
77
+ ---
78
+
79
+ ## The \`surfil-temper:\` Marker Convention
80
+
81
+ Mark deliberate simplifications with a \`surfil-temper:\` comment naming the
82
+ ceiling and upgrade path:
83
+
84
+ \`\`\`
85
+ // surfil-temper: <what was simplified> · ceiling: <known limit> · upgrade: <when/how>
86
+ \`\`\`
87
+
88
+ ---
89
+
90
+ ## Token-Efficiency Rules
91
+
92
+ - Keep functions, modules, and files small.
93
+ - Name things precisely; a precise name eliminates the need for a comment.
94
+ - No speculative comments.
95
+ - Flat over nested.
96
+ - One thing per unit.
97
+ - Delete before adding.
98
+ - Mark deliberate shortcuts with \`surfil-temper:\`.
99
+
100
+ ---
101
+
102
+ ## Levels
103
+
104
+ ### basic
105
+ Restraint Ladder advisory. Non-Negotiable Carve-Outs mandatory.
106
+
107
+ ### full (default)
108
+ Restraint Ladder enforced. Token-Efficiency Rules enforced.
109
+ \`surfil-temper:\` markers required for known ceilings.
110
+ Non-Negotiable Carve-Outs mandatory.
111
+
112
+ ### ultra
113
+ Restraint Ladder extremist. Scope challenges active.
114
+ Every addition must justify its existence. Delete speculatively.
115
+ Non-Negotiable Carve-Outs mandatory.
116
+ `;
117
+ const LEVEL_HEADERS = {
118
+ basic: "<!-- surfil-temper level: basic — Restraint Ladder advisory; Non-Negotiable Carve-Outs mandatory -->",
119
+ full: "<!-- surfil-temper level: full (default) — Restraint Ladder enforced; Token-Efficiency Rules enforced; Non-Negotiable Carve-Outs mandatory -->",
120
+ ultra: "<!-- surfil-temper level: ultra — Restraint Ladder extremist; scope challenges active; Non-Negotiable Carve-Outs mandatory -->",
121
+ };
122
+ const VALID_LEVELS = ["basic", "full", "ultra"];
123
+ exports.VALID_LEVELS = VALID_LEVELS;
124
+ /**
125
+ * Returns the Temper Standard text for the given enforcement level.
126
+ * Invalid levels fall back to "full".
127
+ * All levels include the Non-Negotiable Carve-Outs (never stripped).
128
+ */
129
+ function getStandardForLevel(level) {
130
+ const l = VALID_LEVELS.includes(level)
131
+ ? level
132
+ : "full";
133
+ const header = LEVEL_HEADERS[l] ?? LEVEL_HEADERS["full"];
134
+ return header + "\n\n" + STANDARD_FULL;
135
+ }
136
+ exports.TEMPER_VERSION = "1.0.0";
137
+ //# sourceMappingURL=temper-standard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temper-standard.js","sourceRoot":"","sources":["../src/temper-standard.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AA0HH,kDAMC;AA9HD,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwGrB,CAAC;AAEF,MAAM,aAAa,GAA2B;IAC5C,KAAK,EAAG,sGAAsG;IAC9G,IAAI,EAAG,gJAAgJ;IACvJ,KAAK,EAAE,gIAAgI;CACxI,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAU,CAAC;AAiBhD,oCAAY;AAdrB;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,KAAa;IAC/C,MAAM,CAAC,GAAiB,YAAkC,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxE,CAAC,CAAE,KAAqB;QACxB,CAAC,CAAC,MAAM,CAAC;IACX,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,MAAM,CAAE,CAAC;IAC1D,OAAO,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC;AACzC,CAAC;AAEY,QAAA,cAAc,GAAG,OAAO,CAAC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@surfil/mcp",
3
+ "version": "3.6.6",
4
+ "description": "Surfil MCP server \u2014 bridges MCP-capable editors (Cursor, VS Code, Codex, Zed, Continue, Windsurf, etc.) to the local surfil CLI. Canonical npm name; republishing after npm 24h lock expires.",
5
+ "keywords": [
6
+ "surfil",
7
+ "mcp",
8
+ "ai",
9
+ "session-tracking",
10
+ "observability"
11
+ ],
12
+ "homepage": "https://surfil.com",
13
+ "author": "UpgradIQ, Inc.",
14
+ "license": "SEE LICENSE IN LICENSE",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/UpgradIQ/surfil.git",
18
+ "directory": "surfil-mcp"
19
+ },
20
+ "main": "dist/index.js",
21
+ "bin": {
22
+ "surfil-mcp": "dist/index.js"
23
+ },
24
+ "files": [
25
+ "dist/"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "test": "vitest run",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.9.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.12.0",
40
+ "typescript": "^5.4.5",
41
+ "vitest": "^3.2.0"
42
+ },
43
+ "overrides": {
44
+ "esbuild": "^0.28.1",
45
+ "hono": "^4.12.27"
46
+ }
47
+ }