@tpsdev-ai/flair-mcp 0.53.0 → 0.54.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.
@@ -1,65 +1,48 @@
1
1
  /**
2
- * adapter-surface.ts — the stdio adapter's declared tool set (flair#1575).
2
+ * adapter-surface.ts — the stdio adapter's derived tool set (flair#1580).
3
3
  *
4
- * `@tpsdev-ai/flair-mcp` hand-wires each tool via `server.tool(...)` in
5
- * index.ts. The native `/mcp` handler ships a separate `TOOLS` registry in
6
- * resources/mcp-tools.ts. Those two surfaces drifted: skill_* landed in
7
- * TOOLS for 0.52.0 and never reached this package — the surface Claude Code
8
- * and Cursor actually use.
4
+ * `@tpsdev-ai/flair-mcp` no longer hand-wires per-tool string literals in
5
+ * index.ts. The advertised set is STDIO_TOOL_DESCRIPTORS from the descriptor
6
+ * module vendored at build time into `./tool-descriptors/` (flair#1683;
7
+ * source of truth: packages/flair-tool-descriptors/src/index.ts) — the same
8
+ * descriptors the server TOOLS registry binds to Harper impls. Drift is
9
+ * impossible by construction: a new both-surface descriptor appears here once
10
+ * a FlairClient handler is bound.
9
11
  *
10
- * This module is the reviewed chokepoint for that seam:
12
+ * This module remains the reviewed chokepoint for the stdio ↔ TOOLS seam:
11
13
  *
12
- * 1. `ADAPTER_TOOL_NAMES` is the adapter's declared tool set.
13
- * 2. `parseAdapterToolNames` reads the names actually passed to
14
- * `server.tool(...)` in index.ts, so the declaration cannot outrun
15
- * registration (or vice versa).
16
- * 3. `STDIO_ADAPTER_EXEMPTIONS` is the explicit, reviewed list of names
17
- * that exist on one surface but not the other. A TOOLS name that is
18
- * neither registered here nor exempted is a CI failure — silent drift
19
- * of the class that hid skill_*.
20
- *
21
- * Deriving the adapter's handlers from TOOLS (so a new registry tool appears
22
- * here for free) is the durable structural fix; it does not fit this chip
23
- * because TOOLS is Harper-linked server code and this package talks HTTP via
24
- * FlairClient. Detection + exemption list ships now; derive is a follow-on.
14
+ * 1. `ADAPTER_TOOL_NAMES` is DERIVED from STDIO_TOOL_DESCRIPTORS.
15
+ * 2. `parseAdapterToolNames` still scans for leftover string-literal
16
+ * tool names passed to the MCP SDK — hand-wiring is now a CI failure,
17
+ * not the registration path.
18
+ * 3. `STDIO_ADAPTER_EXEMPTIONS` is DERIVED from descriptor surface flags
19
+ * (the #1578 list, now structural rather than hand-synced).
25
20
  */
26
- /** Tools registered on the stdio adapter via `server.tool(...)` in index.ts. */
27
- export declare const ADAPTER_TOOL_NAMES: readonly ["bootstrap", "flair_orgevent", "flair_workspace_set", "memory_delete", "memory_get", "memory_search", "memory_store", "memory_update", "record_usage", "relationship_store", "skill_get", "skill_search", "skill_store", "soul_get", "soul_set"];
21
+ /** Tools registered on the stdio adapter derived from the shared descriptor list. */
22
+ export declare const ADAPTER_TOOL_NAMES: string[];
28
23
  export type AdapterToolName = (typeof ADAPTER_TOOL_NAMES)[number];
29
24
  /**
30
- * Reviewed exemptions at the stdio-adapter ↔ server TOOLS seam (flair#1575).
31
- *
32
- * A name here is a deliberate, reviewed difference — not silent drift.
33
- * Adding or removing a name is the control: CI fails if an exemption is
34
- * unused (the tool appeared on both sides, or vanished from the side it
35
- * was excused on) or if a non-exempt name exists on only one side.
25
+ * Reviewed one-sided tools at the stdio-adapter ↔ server TOOLS seam.
26
+ * Derived from descriptor `native` / `stdio` flags (flair#1580) — the same
27
+ * names #1578 listed by hand (attention, archive verbs, relationship_store).
36
28
  */
37
29
  export declare const STDIO_ADAPTER_EXEMPTIONS: {
38
- /**
39
- * Present in resources/mcp-tools.ts `TOOLS`, not wired on the stdio adapter.
40
- *
41
- * - attention: native /mcp only (flair#677). mcp-tools.ts's module doc
42
- * explicitly does not mirror it into this package.
43
- * - memory_basement / memory_restore: archive verbs (flair#1472) landed
44
- * on native /mcp; not yet forwarded over FlairClient.
45
- */
46
- readonly registryOnly: readonly ["attention", "memory_basement", "memory_restore"];
47
- /**
48
- * Wired on the stdio adapter, absent from `TOOLS`.
49
- *
50
- * - relationship_store: the adapter predates the record-types mcp
51
- * declaration. Relationship has no `RECORD_TYPES.mcp` field, so TOOLS
52
- * ships zero relationship_* names. The adapter still exposes the triple
53
- * write (FlairClient.relationship.write).
54
- */
55
- readonly adapterOnly: readonly ["relationship_store"];
30
+ readonly registryOnly: string[];
31
+ readonly adapterOnly: string[];
56
32
  };
57
33
  /**
58
- * Collect `server.tool("name", ...)` registrations from adapter source.
59
- * Plain string scan — the first string literal argument is the tool name.
34
+ * Collect leftover string-literal tool registrations from adapter source.
35
+ * After #1580 the derived registrar uses `server.tool(d.name, ...)`, so this
36
+ * scan should return empty. A new literal is a CI failure.
60
37
  * Does not use `new RegExp` built from runtime input (CodeQL js/regex-injection).
61
38
  */
62
39
  export declare function parseAdapterToolNames(source: string): string[];
40
+ /**
41
+ * Handler keys from `STDIO_TOOL_HANDLERS` in adapter-tools.ts source.
42
+ * Root unit tests must not import adapter-tools.ts — that module loads
43
+ * `@tpsdev-ai/flair-client` (built later in the unit lane).
44
+ */
45
+ export declare function parseStdioHandlerNames(source: string): string[];
63
46
  export interface AdapterRegistryParity {
64
47
  /** TOOLS names the adapter neither registers nor exempts. */
65
48
  missingFromAdapter: string[];
@@ -71,5 +54,14 @@ export interface AdapterRegistryParity {
71
54
  /**
72
55
  * Compare the stdio adapter's tool set to the server TOOLS registry.
73
56
  * Equal after applying the reviewed exemption list — otherwise drift.
57
+ * Kept from #1578 as the migration tripwire; #1580 also asserts
58
+ * derived set == descriptor set structurally.
74
59
  */
75
60
  export declare function adapterRegistryParity(registryNames: readonly string[], adapterNames: readonly string[]): AdapterRegistryParity;
61
+ /**
62
+ * Structural #1580 assert: the bound handler set equals the stdio descriptor set.
63
+ */
64
+ export declare function derivedDescriptorParity(handlerNames: readonly string[], descriptorNamesList?: readonly string[]): {
65
+ missingHandlers: string[];
66
+ extraHandlers: string[];
67
+ };
@@ -1,77 +1,39 @@
1
1
  /**
2
- * adapter-surface.ts — the stdio adapter's declared tool set (flair#1575).
2
+ * adapter-surface.ts — the stdio adapter's derived tool set (flair#1580).
3
3
  *
4
- * `@tpsdev-ai/flair-mcp` hand-wires each tool via `server.tool(...)` in
5
- * index.ts. The native `/mcp` handler ships a separate `TOOLS` registry in
6
- * resources/mcp-tools.ts. Those two surfaces drifted: skill_* landed in
7
- * TOOLS for 0.52.0 and never reached this package — the surface Claude Code
8
- * and Cursor actually use.
4
+ * `@tpsdev-ai/flair-mcp` no longer hand-wires per-tool string literals in
5
+ * index.ts. The advertised set is STDIO_TOOL_DESCRIPTORS from the descriptor
6
+ * module vendored at build time into `./tool-descriptors/` (flair#1683;
7
+ * source of truth: packages/flair-tool-descriptors/src/index.ts) — the same
8
+ * descriptors the server TOOLS registry binds to Harper impls. Drift is
9
+ * impossible by construction: a new both-surface descriptor appears here once
10
+ * a FlairClient handler is bound.
9
11
  *
10
- * This module is the reviewed chokepoint for that seam:
12
+ * This module remains the reviewed chokepoint for the stdio ↔ TOOLS seam:
11
13
  *
12
- * 1. `ADAPTER_TOOL_NAMES` is the adapter's declared tool set.
13
- * 2. `parseAdapterToolNames` reads the names actually passed to
14
- * `server.tool(...)` in index.ts, so the declaration cannot outrun
15
- * registration (or vice versa).
16
- * 3. `STDIO_ADAPTER_EXEMPTIONS` is the explicit, reviewed list of names
17
- * that exist on one surface but not the other. A TOOLS name that is
18
- * neither registered here nor exempted is a CI failure — silent drift
19
- * of the class that hid skill_*.
20
- *
21
- * Deriving the adapter's handlers from TOOLS (so a new registry tool appears
22
- * here for free) is the durable structural fix; it does not fit this chip
23
- * because TOOLS is Harper-linked server code and this package talks HTTP via
24
- * FlairClient. Detection + exemption list ships now; derive is a follow-on.
14
+ * 1. `ADAPTER_TOOL_NAMES` is DERIVED from STDIO_TOOL_DESCRIPTORS.
15
+ * 2. `parseAdapterToolNames` still scans for leftover string-literal
16
+ * tool names passed to the MCP SDK — hand-wiring is now a CI failure,
17
+ * not the registration path.
18
+ * 3. `STDIO_ADAPTER_EXEMPTIONS` is DERIVED from descriptor surface flags
19
+ * (the #1578 list, now structural rather than hand-synced).
25
20
  */
26
- /** Tools registered on the stdio adapter via `server.tool(...)` in index.ts. */
27
- export const ADAPTER_TOOL_NAMES = [
28
- "bootstrap",
29
- "flair_orgevent",
30
- "flair_workspace_set",
31
- "memory_delete",
32
- "memory_get",
33
- "memory_search",
34
- "memory_store",
35
- "memory_update",
36
- "record_usage",
37
- "relationship_store",
38
- "skill_get",
39
- "skill_search",
40
- "skill_store",
41
- "soul_get",
42
- "soul_set",
43
- ];
21
+ import { STDIO_TOOL_DESCRIPTORS, SURFACE_EXEMPTIONS, descriptorNames, } from "./tool-descriptors/index.js";
22
+ /** Tools registered on the stdio adapter — derived from the shared descriptor list. */
23
+ export const ADAPTER_TOOL_NAMES = descriptorNames(STDIO_TOOL_DESCRIPTORS);
44
24
  /**
45
- * Reviewed exemptions at the stdio-adapter ↔ server TOOLS seam (flair#1575).
46
- *
47
- * A name here is a deliberate, reviewed difference — not silent drift.
48
- * Adding or removing a name is the control: CI fails if an exemption is
49
- * unused (the tool appeared on both sides, or vanished from the side it
50
- * was excused on) or if a non-exempt name exists on only one side.
25
+ * Reviewed one-sided tools at the stdio-adapter ↔ server TOOLS seam.
26
+ * Derived from descriptor `native` / `stdio` flags (flair#1580) — the same
27
+ * names #1578 listed by hand (attention, archive verbs, relationship_store).
51
28
  */
52
29
  export const STDIO_ADAPTER_EXEMPTIONS = {
53
- /**
54
- * Present in resources/mcp-tools.ts `TOOLS`, not wired on the stdio adapter.
55
- *
56
- * - attention: native /mcp only (flair#677). mcp-tools.ts's module doc
57
- * explicitly does not mirror it into this package.
58
- * - memory_basement / memory_restore: archive verbs (flair#1472) landed
59
- * on native /mcp; not yet forwarded over FlairClient.
60
- */
61
- registryOnly: ["attention", "memory_basement", "memory_restore"],
62
- /**
63
- * Wired on the stdio adapter, absent from `TOOLS`.
64
- *
65
- * - relationship_store: the adapter predates the record-types mcp
66
- * declaration. Relationship has no `RECORD_TYPES.mcp` field, so TOOLS
67
- * ships zero relationship_* names. The adapter still exposes the triple
68
- * write (FlairClient.relationship.write).
69
- */
70
- adapterOnly: ["relationship_store"],
30
+ registryOnly: SURFACE_EXEMPTIONS.registryOnly,
31
+ adapterOnly: SURFACE_EXEMPTIONS.adapterOnly,
71
32
  };
72
33
  /**
73
- * Collect `server.tool("name", ...)` registrations from adapter source.
74
- * Plain string scan — the first string literal argument is the tool name.
34
+ * Collect leftover string-literal tool registrations from adapter source.
35
+ * After #1580 the derived registrar uses `server.tool(d.name, ...)`, so this
36
+ * scan should return empty. A new literal is a CI failure.
75
37
  * Does not use `new RegExp` built from runtime input (CodeQL js/regex-injection).
76
38
  */
77
39
  export function parseAdapterToolNames(source) {
@@ -82,9 +44,48 @@ export function parseAdapterToolNames(source) {
82
44
  names.push(match[1]);
83
45
  return names;
84
46
  }
47
+ /**
48
+ * Handler keys from `STDIO_TOOL_HANDLERS` in adapter-tools.ts source.
49
+ * Root unit tests must not import adapter-tools.ts — that module loads
50
+ * `@tpsdev-ai/flair-client` (built later in the unit lane).
51
+ */
52
+ export function parseStdioHandlerNames(source) {
53
+ const marker = "export const STDIO_TOOL_HANDLERS";
54
+ const start = source.indexOf(marker);
55
+ if (start < 0)
56
+ return [];
57
+ const open = source.indexOf("{", start);
58
+ if (open < 0)
59
+ return [];
60
+ let depth = 0;
61
+ let close = -1;
62
+ for (let i = open; i < source.length; i++) {
63
+ const c = source[i];
64
+ if (c === "{")
65
+ depth++;
66
+ else if (c === "}") {
67
+ depth--;
68
+ if (depth === 0) {
69
+ close = i;
70
+ break;
71
+ }
72
+ }
73
+ }
74
+ if (close < 0)
75
+ return [];
76
+ const names = [];
77
+ for (const line of source.slice(open + 1, close).split("\n")) {
78
+ const m = line.match(/^\s*([a-z][a-z0-9_]*)\s*,?\s*$/);
79
+ if (m)
80
+ names.push(m[1]);
81
+ }
82
+ return names.sort();
83
+ }
85
84
  /**
86
85
  * Compare the stdio adapter's tool set to the server TOOLS registry.
87
86
  * Equal after applying the reviewed exemption list — otherwise drift.
87
+ * Kept from #1578 as the migration tripwire; #1580 also asserts
88
+ * derived set == descriptor set structurally.
88
89
  */
89
90
  export function adapterRegistryParity(registryNames, adapterNames) {
90
91
  const registry = new Set(registryNames);
@@ -103,3 +104,14 @@ export function adapterRegistryParity(registryNames, adapterNames) {
103
104
  ].sort();
104
105
  return { missingFromAdapter, extraOnAdapter, staleExemptions };
105
106
  }
107
+ /**
108
+ * Structural #1580 assert: the bound handler set equals the stdio descriptor set.
109
+ */
110
+ export function derivedDescriptorParity(handlerNames, descriptorNamesList = ADAPTER_TOOL_NAMES) {
111
+ const handlers = new Set(handlerNames);
112
+ const descriptors = new Set(descriptorNamesList);
113
+ return {
114
+ missingHandlers: [...descriptors].filter((n) => !handlers.has(n)).sort(),
115
+ extraHandlers: [...handlers].filter((n) => !descriptors.has(n)).sort(),
116
+ };
117
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Stdio adapter bindings (flair#1580).
3
+ *
4
+ * The tool SET is derived from STDIO_TOOL_DESCRIPTORS. This module only
5
+ * supplies FlairClient HTTP handlers — one per stdio descriptor. A new
6
+ * descriptor with no handler (or a handler with no descriptor) fails at
7
+ * registration, so the surfaces cannot drift by omission.
8
+ */
9
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import type { FlairClient } from "@tpsdev-ai/flair-client";
11
+ import { type PresenceActivity } from "./presence.js";
12
+ export interface AdapterContext {
13
+ flair: FlairClient;
14
+ agentId: string;
15
+ heartbeat: (activity?: PresenceActivity) => void;
16
+ rememberTask: (task: string | undefined) => void;
17
+ }
18
+ type ToolResult = {
19
+ content: Array<{
20
+ type: "text";
21
+ text: string;
22
+ }>;
23
+ isError?: boolean;
24
+ structuredContent?: Record<string, unknown>;
25
+ };
26
+ type StdioHandler = (args: Record<string, any>, ctx: AdapterContext) => Promise<ToolResult>;
27
+ /** FlairClient bindings keyed by descriptor name — the adapter-side impl map. */
28
+ export declare const STDIO_TOOL_HANDLERS: Record<string, StdioHandler>;
29
+ export declare function stdioHandlerNames(): string[];
30
+ /**
31
+ * Register every stdio descriptor on the MCP server. The advertised set is
32
+ * STDIO_TOOL_DESCRIPTORS — not a hand-written per-tool literal list.
33
+ */
34
+ export declare function registerStdioTools(server: McpServer, ctx: AdapterContext): string[];
35
+ export {};