@tpsdev-ai/flair-mcp 0.52.0 → 0.54.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.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * skills.ts — stdio-adapter shaping for skill_* tools (flair#1575).
3
+ *
4
+ * Native `/mcp` implements skill_store / skill_search / skill_get as thin
5
+ * wrappers over Memory / SemanticSearch (resources/mcp-tools.ts). This
6
+ * package talks HTTP via FlairClient, so the wrappers here only shape
7
+ * the request body and the client-visible result — they re-implement no
8
+ * write, recall, or scoping logic. Server-side SkillScan, forced
9
+ * durability=persistent, and resolveReadScope still run on the daemon.
10
+ *
11
+ * Progressive disclosure matches the native contract: skill_search returns
12
+ * catalog cards (never `content` / embedding); skill_get is the disclosure
13
+ * step for the full procedure. skill_get always strips embedding /
14
+ * embeddingModel (flair#1579) — there is no includeEmbedding opt-in.
15
+ */
16
+ /** The tag that marks a Memory as a skill (resources/skill-write.ts). */
17
+ export declare const SKILL_TAG = "skill";
18
+ export declare function isSkillRecord(record: unknown): boolean;
19
+ /**
20
+ * Lightweight skill CATALOG card — id/name/trigger/description/tags/agentId.
21
+ * `name`/`description` live in the opaque metadata JSON blob; a corrupt or
22
+ * absent blob simply yields no name/desc. `content` and the raw embedding
23
+ * are deliberately absent (skill_search progressive-disclosure contract).
24
+ */
25
+ export declare function projectSkillCard(r: unknown): Record<string, unknown>;
26
+ export declare function stripInternalMemoryFields<T extends Record<string, unknown>>(value: T): T;
27
+ /** Body for PUT /Memory/:id — matches native skill_store's Memory.post() shape. */
28
+ export declare function buildSkillStoreBody(opts: {
29
+ agentId: string;
30
+ content: string;
31
+ trigger?: string;
32
+ name?: string;
33
+ description?: string;
34
+ tags?: string[];
35
+ claimedClient?: string;
36
+ }): {
37
+ id: string;
38
+ body: Record<string, unknown>;
39
+ };
40
+ /** SemanticSearch body for skill_search — no agentId (scope is the signed identity). */
41
+ export declare function buildSkillSearchBody(opts: {
42
+ task: string;
43
+ limit?: number;
44
+ }): Record<string, unknown>;
45
+ /**
46
+ * Project a SemanticSearch response onto catalog cards. A guard/error payload
47
+ * (no `results` array) is returned untouched so the caller can surface it.
48
+ */
49
+ export declare function projectSkillSearchResponse(res: unknown): unknown;
50
+ export declare function formatSkillCatalog(results: Array<Record<string, unknown>>): string;
package/dist/skills.js ADDED
@@ -0,0 +1,120 @@
1
+ /**
2
+ * skills.ts — stdio-adapter shaping for skill_* tools (flair#1575).
3
+ *
4
+ * Native `/mcp` implements skill_store / skill_search / skill_get as thin
5
+ * wrappers over Memory / SemanticSearch (resources/mcp-tools.ts). This
6
+ * package talks HTTP via FlairClient, so the wrappers here only shape
7
+ * the request body and the client-visible result — they re-implement no
8
+ * write, recall, or scoping logic. Server-side SkillScan, forced
9
+ * durability=persistent, and resolveReadScope still run on the daemon.
10
+ *
11
+ * Progressive disclosure matches the native contract: skill_search returns
12
+ * catalog cards (never `content` / embedding); skill_get is the disclosure
13
+ * step for the full procedure. skill_get always strips embedding /
14
+ * embeddingModel (flair#1579) — there is no includeEmbedding opt-in.
15
+ */
16
+ /** The tag that marks a Memory as a skill (resources/skill-write.ts). */
17
+ export const SKILL_TAG = "skill";
18
+ const INTERNAL_MEMORY_FIELDS = ["embedding", "embeddingModel"];
19
+ export function isSkillRecord(record) {
20
+ const tags = record?.tags;
21
+ return Array.isArray(tags) && tags.includes(SKILL_TAG);
22
+ }
23
+ /**
24
+ * Lightweight skill CATALOG card — id/name/trigger/description/tags/agentId.
25
+ * `name`/`description` live in the opaque metadata JSON blob; a corrupt or
26
+ * absent blob simply yields no name/desc. `content` and the raw embedding
27
+ * are deliberately absent (skill_search progressive-disclosure contract).
28
+ */
29
+ export function projectSkillCard(r) {
30
+ const row = (r ?? {});
31
+ let name;
32
+ let description;
33
+ if (typeof row.metadata === "string" && row.metadata.length > 0) {
34
+ try {
35
+ const meta = JSON.parse(row.metadata);
36
+ if (meta && typeof meta === "object") {
37
+ if (typeof meta.name === "string")
38
+ name = meta.name;
39
+ if (typeof meta.description === "string")
40
+ description = meta.description;
41
+ }
42
+ }
43
+ catch {
44
+ /* opaque/corrupt metadata → no name/description on the card */
45
+ }
46
+ }
47
+ return {
48
+ id: row.id,
49
+ name,
50
+ trigger: row.trigger,
51
+ description,
52
+ tags: row.tags,
53
+ agentId: row.agentId,
54
+ };
55
+ }
56
+ export function stripInternalMemoryFields(value) {
57
+ const out = { ...value };
58
+ for (const field of INTERNAL_MEMORY_FIELDS)
59
+ delete out[field];
60
+ return out;
61
+ }
62
+ /** Body for PUT /Memory/:id — matches native skill_store's Memory.post() shape. */
63
+ export function buildSkillStoreBody(opts) {
64
+ const id = `${opts.agentId}-${crypto.randomUUID()}`;
65
+ const body = {
66
+ id,
67
+ agentId: opts.agentId,
68
+ content: opts.content,
69
+ tags: [SKILL_TAG, ...(Array.isArray(opts.tags) ? opts.tags : [])],
70
+ };
71
+ // durability is NOT set — the server forces persistent for skill-tagged
72
+ // writes and rejects an explicit ephemeral/session.
73
+ if (typeof opts.trigger === "string" && opts.trigger.length > 0)
74
+ body.trigger = opts.trigger;
75
+ if (opts.claimedClient)
76
+ body.claimedClient = opts.claimedClient;
77
+ const meta = {};
78
+ if (typeof opts.name === "string" && opts.name.length > 0)
79
+ meta.name = opts.name;
80
+ if (typeof opts.description === "string" && opts.description.length > 0)
81
+ meta.description = opts.description;
82
+ if (Object.keys(meta).length > 0)
83
+ body.metadata = JSON.stringify(meta);
84
+ return { id, body };
85
+ }
86
+ /** SemanticSearch body for skill_search — no agentId (scope is the signed identity). */
87
+ export function buildSkillSearchBody(opts) {
88
+ return {
89
+ q: opts.task,
90
+ tag: SKILL_TAG,
91
+ limit: opts.limit ?? 5,
92
+ includeMetadata: true,
93
+ includeTrigger: true,
94
+ };
95
+ }
96
+ /**
97
+ * Project a SemanticSearch response onto catalog cards. A guard/error payload
98
+ * (no `results` array) is returned untouched so the caller can surface it.
99
+ */
100
+ export function projectSkillSearchResponse(res) {
101
+ if (!res || typeof res !== "object" || !Array.isArray(res.results)) {
102
+ return res;
103
+ }
104
+ const payload = res;
105
+ return { ...payload, results: payload.results.map(projectSkillCard) };
106
+ }
107
+ export function formatSkillCatalog(results) {
108
+ if (results.length === 0)
109
+ return "No matching skills found.";
110
+ return results
111
+ .map((card, i) => {
112
+ const title = typeof card.name === "string" && card.name.length > 0 ? card.name : "(unnamed skill)";
113
+ const trigger = typeof card.trigger === "string" && card.trigger.length > 0 ? card.trigger : "";
114
+ const desc = typeof card.description === "string" && card.description.length > 0 ? card.description : "";
115
+ const idStr = card.id ? `id:${card.id}` : "";
116
+ const header = [title, trigger, idStr].filter(Boolean).join(" — ");
117
+ return desc ? `${i + 1}. ${header}\n ${desc}` : `${i + 1}. ${header}`;
118
+ })
119
+ .join("\n");
120
+ }
@@ -0,0 +1,19 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ Copyright 2026 TPS Dev AI
8
+
9
+ Licensed under the Apache License, Version 2.0 (the "License");
10
+ you may not use this file except in compliance with the License.
11
+ You may obtain a copy of the License at
12
+
13
+ http://www.apache.org/licenses/LICENSE-2.0
14
+
15
+ Unless required by applicable law or agreed to in writing, software
16
+ distributed under the License is distributed on an "AS IS" BASIS,
17
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ See the License for the specific language governing permissions and
19
+ limitations under the License.
@@ -0,0 +1,22 @@
1
+ # @tpsdev-ai/flair-tool-descriptors
2
+
3
+ Transport-agnostic MCP tool descriptors for [Flair](https://tps.dev/#flair).
4
+
5
+ This package is **pure data and types**: tool name, description, JSON Schema
6
+ `inputSchema`, output shape, and reviewed surface flags. It imports neither
7
+ Harper nor FlairClient. The Flair server binds each native descriptor to its
8
+ Harper implementation; `@tpsdev-ai/flair-mcp` binds each stdio descriptor to a
9
+ FlairClient HTTP call. Both tool sets are derived from this list, so a new
10
+ descriptor appears on every listed surface with zero hand-wiring (flair#1580).
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @tpsdev-ai/flair-tool-descriptors
16
+ ```
17
+
18
+ ## Surfaces
19
+
20
+ `native` and `stdio` default to true. Set either to `false` for a reviewed
21
+ one-sided tool (`attention` is native-only; `relationship_store` is
22
+ stdio-only). The #1578 exemption list is derived from those flags.
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Transport-agnostic MCP tool descriptors (flair#1580).
3
+ *
4
+ * Pure data + types: name, description, inputSchema, output shape, and
5
+ * reviewed surface flags. No Harper, no FlairClient, no Zod, no HTTP.
6
+ *
7
+ * The server TOOLS registry binds each native descriptor to its Harper impl.
8
+ * The flair-mcp stdio adapter binds each stdio descriptor to a FlairClient
9
+ * call. Both tool sets are DERIVED from this list — a new descriptor appears
10
+ * on every surface that lists it, with zero hand-wiring.
11
+ */
12
+ /** JSON Schema object used as MCP tools/list inputSchema. */
13
+ export interface JsonSchemaObject {
14
+ type: "object";
15
+ properties: Record<string, JsonSchemaProperty>;
16
+ required?: string[];
17
+ }
18
+ export interface JsonSchemaProperty {
19
+ type?: string;
20
+ description?: string;
21
+ enum?: string[];
22
+ items?: {
23
+ type?: string;
24
+ };
25
+ default?: unknown;
26
+ }
27
+ /** MCP tool descriptor as returned by tools/list. */
28
+ export interface McpToolDef {
29
+ name: string;
30
+ description: string;
31
+ inputSchema: JsonSchemaObject;
32
+ annotations?: Record<string, unknown>;
33
+ }
34
+ /**
35
+ * One MCP-facing tool. `native` / `stdio` default true — omit both and the
36
+ * tool appears on every surface. Set false for a reviewed one-sided tool
37
+ * (the #1578 exemption list is derived from these flags).
38
+ */
39
+ export interface ToolDescriptor {
40
+ name: string;
41
+ description: string;
42
+ inputSchema: JsonSchemaObject;
43
+ /** One-line output shape (MCP metadata). Native conformance contracts pin this as `summary`. */
44
+ outputShape: string;
45
+ annotations?: Record<string, unknown>;
46
+ /** When false, native /mcp does not bind this tool. Default true. */
47
+ native?: boolean;
48
+ /** When false, the stdio adapter does not bind this tool. Default true. */
49
+ stdio?: boolean;
50
+ /** Stdio-only description when the HTTP path differs from native /mcp policy. */
51
+ stdioDescription?: string;
52
+ /** Properties advertised on native /mcp only (reviewed, e.g. flair#1579). */
53
+ stdioOmitProperties?: readonly string[];
54
+ /** Properties advertised on the stdio adapter only (reviewed). */
55
+ stdioExtraProperties?: Record<string, JsonSchemaProperty>;
56
+ }
57
+ export declare function isNativeTool(d: ToolDescriptor): boolean;
58
+ export declare function isStdioTool(d: ToolDescriptor): boolean;
59
+ export declare function toMcpToolDef(d: ToolDescriptor): McpToolDef;
60
+ /** Native tools/list def, minus reviewed stdio-only omissions. */
61
+ export declare function toStdioMcpToolDef(d: ToolDescriptor): McpToolDef;
62
+ export declare function descriptorNames(descriptors: readonly ToolDescriptor[]): string[];
63
+ export declare const TOOL_DESCRIPTORS: readonly ToolDescriptor[];
64
+ export declare const NATIVE_TOOL_DESCRIPTORS: readonly ToolDescriptor[];
65
+ export declare const STDIO_TOOL_DESCRIPTORS: readonly ToolDescriptor[];
66
+ /** Derived #1578 exemption list — one-sided by construction, not hand-synced. */
67
+ export declare const SURFACE_EXEMPTIONS: {
68
+ readonly registryOnly: string[];
69
+ readonly adapterOnly: string[];
70
+ };