@tacitai/mcp-server 0.2.0 → 0.3.0

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/dist/index.js CHANGED
@@ -56,6 +56,7 @@ import { registerPeopleTools } from './tools/people.js';
56
56
  import { registerLakeStructureTools } from './tools/lake-structure.js';
57
57
  import { registerResearchTools } from './tools/research.js';
58
58
  import { registerGmTools } from './tools/gm.js';
59
+ import { registerSkillTools } from './tools/skills.js';
59
60
  import { registerPrompts } from './prompts.js';
60
61
  import { getRequestPrincipal } from './client.js';
61
62
  // Setup wizard (MV-1057h / W5)
@@ -136,7 +137,7 @@ async function run() {
136
137
  }
137
138
  checkProfileExpiry(profile);
138
139
  checkCompatibility();
139
- const server = new McpServer({ name: '@tacitai/mcp-server', version: '0.2.0' }, { capabilities: { tools: {}, prompts: {} } });
140
+ const server = new McpServer({ name: '@tacitai/mcp-server', version: '0.3.0' }, { capabilities: { tools: {}, prompts: {} } });
140
141
  const isHttpMode = process.env['MCP_TRANSPORT'] === 'http';
141
142
  let clientInstance = null;
142
143
  const getClient = async () => {
@@ -176,6 +177,7 @@ async function run() {
176
177
  registerLakeStructureTools(server, getClient);
177
178
  registerGmTools(server, getClient);
178
179
  registerResearchTools(server, getClient, getRequestPrincipal);
180
+ registerSkillTools(server, getClient);
179
181
  registerPrompts(server);
180
182
  if (process.env['MCP_TRANSPORT'] === 'http') {
181
183
  await startHttpTransport(server);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Compile-time tool classification. Governs which tools may be called over HTTPS.
3
- * Partition: 6 stdio_only + 15 admin_only + 2 gate_only + 108 https = 131.
3
+ * Partition: 6 stdio_only + 15 admin_only + 2 gate_only + 110 https = 133.
4
4
  */
5
5
  export type ToolTransport = 'https' | 'stdio_only' | 'admin_only' | 'gate_only';
6
6
  export type ToolClass = 'read' | 'write' | 'admin' | 'dispatch';
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  /**
3
3
  * Compile-time tool classification. Governs which tools may be called over HTTPS.
4
- * Partition: 6 stdio_only + 15 admin_only + 2 gate_only + 108 https = 131.
4
+ * Partition: 6 stdio_only + 15 admin_only + 2 gate_only + 110 https = 133.
5
5
  */
6
6
  const STDIO_ONLY = [
7
7
  'tacit_ingest_file',
@@ -72,6 +72,7 @@ const READ_TOOLS = [
72
72
  'tacit_lake_taxonomy_browse',
73
73
  'tacit_list_annotations',
74
74
  'tacit_list_deliverables',
75
+ 'tacit_list_skills',
75
76
  'tacit_list_people',
76
77
  'tacit_list_workspaces',
77
78
  'tacit_outbox_status',
@@ -97,6 +98,7 @@ const DISPATCH_TOOLS = [
97
98
  'tacit_kb_pull_source',
98
99
  'tacit_lake_trigger_sync',
99
100
  'tacit_research_launch',
101
+ 'tacit_run_skill',
100
102
  ];
101
103
  const WRITE_TOOLS = [
102
104
  'tacit_agent_decide',
@@ -176,8 +178,8 @@ function build() {
176
178
  if (!exclusive.has(n))
177
179
  add(n, classOf(n), 'https', false);
178
180
  }
179
- if (map.size !== 131)
180
- throw new Error(`tool registry expected 131 tools, got ${map.size}`);
181
+ if (map.size !== 133)
182
+ throw new Error(`tool registry expected 133 tools, got ${map.size}`);
181
183
  return map;
182
184
  }
183
185
  export const TOOL_REGISTRY = build();
@@ -0,0 +1,9 @@
1
+ /**
2
+ * tacit_list_skills / tacit_run_skill — MCP skill orchestration (MV-1533 W6)
3
+ *
4
+ * GET /api/v1/internal/skills — list available exec skills
5
+ * POST /api/v1/converse — invoke a skill by hint (SSE stream)
6
+ */
7
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
+ import { TacitClient } from '../client.js';
9
+ export declare function registerSkillTools(server: McpServer, getClientFn: () => Promise<TacitClient>): void;
@@ -0,0 +1,98 @@
1
+ // SPDX-License-Identifier: MIT
2
+ /**
3
+ * tacit_list_skills / tacit_run_skill — MCP skill orchestration (MV-1533 W6)
4
+ *
5
+ * GET /api/v1/internal/skills — list available exec skills
6
+ * POST /api/v1/converse — invoke a skill by hint (SSE stream)
7
+ */
8
+ import { z } from 'zod';
9
+ export function registerSkillTools(server, getClientFn) {
10
+ // --- tacit_list_skills ---
11
+ server.tool('tacit_list_skills', 'List available TACIT exec skills with their domains, descriptions, and access levels.', {}, async () => {
12
+ const client = await getClientFn();
13
+ try {
14
+ const data = await client.get('/api/v1/internal/skills');
15
+ return {
16
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
17
+ };
18
+ }
19
+ catch (err) {
20
+ const msg = err instanceof Error ? err.message : String(err);
21
+ return { content: [{ type: 'text', text: `Error listing skills: ${msg}` }], isError: true };
22
+ }
23
+ });
24
+ // --- tacit_run_skill ---
25
+ server.tool('tacit_run_skill', 'Run a TACIT exec skill by name. Sends the message through the converse pipeline with skill_hint routing. Returns the skill response, which may include tool calls, structured answers, or approval requests.', {
26
+ skill_id: z.string().min(1).describe('The skill domain ID (e.g., "pyr-exec", "lake-exec", "kb-exec", "sales-exec", "gm-exec")'),
27
+ message: z.string().min(1).describe('The natural-language instruction for the skill'),
28
+ session_id: z.string().optional().describe('Existing converse session UUID to continue; omit for a new session'),
29
+ }, async (args) => {
30
+ const client = await getClientFn();
31
+ // Validate skill_id against the catalog
32
+ try {
33
+ const catalog = await client.get('/api/v1/internal/skills');
34
+ const validDomains = catalog.skills.map((s) => s.domain);
35
+ if (!validDomains.includes(args.skill_id)) {
36
+ return {
37
+ content: [{ type: 'text', text: `Unknown skill_id "${args.skill_id}". Valid skills: ${validDomains.join(', ')}` }],
38
+ isError: true,
39
+ };
40
+ }
41
+ }
42
+ catch {
43
+ // Catalog unreachable — proceed anyway, backend will validate
44
+ }
45
+ const body = {
46
+ message: args.message,
47
+ skill_hint: args.skill_id,
48
+ channel: 'mcp',
49
+ };
50
+ if (args.session_id)
51
+ body['session_id'] = args.session_id;
52
+ try {
53
+ const chunks = [];
54
+ let sessionId = '';
55
+ let structuredAnswer = null;
56
+ let pendingApproval = null;
57
+ for await (const chunk of client.postSSE('/api/v1/converse', body)) {
58
+ try {
59
+ const parsed = JSON.parse(chunk);
60
+ if (parsed.type === 'session_start')
61
+ sessionId = parsed.session_id;
62
+ else if (parsed.type === 'token')
63
+ chunks.push(parsed.delta);
64
+ else if (parsed.type === 'structured_answer')
65
+ structuredAnswer = parsed.data;
66
+ else if (parsed.type === 'pending_approval')
67
+ pendingApproval = parsed;
68
+ else if (parsed.type === 'tool_call_end') {
69
+ if (parsed.result)
70
+ chunks.push(typeof parsed.result === 'string' ? parsed.result : JSON.stringify(parsed.result));
71
+ }
72
+ }
73
+ catch {
74
+ chunks.push(chunk);
75
+ }
76
+ }
77
+ const text = chunks.join('');
78
+ const result = {
79
+ skill_id: args.skill_id,
80
+ session_id: sessionId,
81
+ response: text,
82
+ };
83
+ if (structuredAnswer)
84
+ result['structured_answer'] = structuredAnswer;
85
+ if (pendingApproval) {
86
+ result['pending_approval'] = pendingApproval;
87
+ result['instructions'] = 'This operation requires approval. Use tacit_converse with the session_id and confirm_token to approve or reject.';
88
+ }
89
+ return {
90
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
91
+ };
92
+ }
93
+ catch (err) {
94
+ const msg = err instanceof Error ? err.message : String(err);
95
+ return { content: [{ type: 'text', text: `Error running skill ${args.skill_id}: ${msg}` }], isError: true };
96
+ }
97
+ });
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tacitai/mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "stdio MCP server wrapping Tacit /api/v1 REST/SSE API",
5
5
  "license": "MIT",
6
6
  "repository": {