@tacitai/mcp-server 0.1.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.
@@ -0,0 +1,68 @@
1
+ /**
2
+ * tacit_synthesize — canonical synthesis tool
3
+ *
4
+ * JSON path (stream:false): POST /api/v1/mind/synthesize
5
+ * SSE path (stream:true): POST /api/v1/mind/synthesize/stream
6
+ *
7
+ * Aliases: tacit_ask / tacit_compose route to this same handler.
8
+ * stream:true selects the SSE variant and returns aggregated chunks.
9
+ */
10
+ import { z } from 'zod';
11
+ import { TacitClient } from '../client.js';
12
+ export declare const synthesizeInputSchema: z.ZodObject<{
13
+ query: z.ZodString;
14
+ scope: z.ZodOptional<z.ZodString>;
15
+ stream: z.ZodOptional<z.ZodBoolean>;
16
+ }, "strip", z.ZodTypeAny, {
17
+ query: string;
18
+ stream?: boolean | undefined;
19
+ scope?: string | undefined;
20
+ }, {
21
+ query: string;
22
+ stream?: boolean | undefined;
23
+ scope?: string | undefined;
24
+ }>;
25
+ export type SynthesizeInput = z.infer<typeof synthesizeInputSchema>;
26
+ export declare const SYNTHESIZE_TOOL_DEF: {
27
+ name: "tacit_synthesize";
28
+ description: string;
29
+ inputSchema: {
30
+ type: "object";
31
+ properties: {
32
+ query: {
33
+ type: string;
34
+ description: string;
35
+ };
36
+ scope: {
37
+ type: string;
38
+ description: string;
39
+ };
40
+ stream: {
41
+ type: string;
42
+ description: string;
43
+ };
44
+ };
45
+ required: string[];
46
+ };
47
+ };
48
+ export interface ToolRequest {
49
+ execute(): Promise<{
50
+ content: Array<{
51
+ type: 'text';
52
+ text: string;
53
+ }>;
54
+ isError?: boolean;
55
+ }>;
56
+ }
57
+ /**
58
+ * Build a synthesize request object. Call .execute() to perform the HTTP call.
59
+ * Exported for testability (allows injecting a mock TacitClient).
60
+ */
61
+ export declare function buildSynthesizeRequest(client: TacitClient, input: SynthesizeInput): ToolRequest;
62
+ export declare function handleSynthesize(args: unknown): Promise<{
63
+ content: Array<{
64
+ type: 'text';
65
+ text: string;
66
+ }>;
67
+ isError?: boolean;
68
+ }>;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: MIT
3
+ /**
4
+ * tacit_synthesize — canonical synthesis tool
5
+ *
6
+ * JSON path (stream:false): POST /api/v1/mind/synthesize
7
+ * SSE path (stream:true): POST /api/v1/mind/synthesize/stream
8
+ *
9
+ * Aliases: tacit_ask / tacit_compose route to this same handler.
10
+ * stream:true selects the SSE variant and returns aggregated chunks.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.SYNTHESIZE_TOOL_DEF = exports.synthesizeInputSchema = void 0;
14
+ exports.buildSynthesizeRequest = buildSynthesizeRequest;
15
+ exports.handleSynthesize = handleSynthesize;
16
+ const zod_1 = require("zod");
17
+ const client_js_1 = require("../client.js");
18
+ exports.synthesizeInputSchema = zod_1.z.object({
19
+ query: zod_1.z.string().min(1).describe('Question or synthesis prompt'),
20
+ scope: zod_1.z.string().optional().describe('Optional scope filter (e.g. portfolio or program id)'),
21
+ stream: zod_1.z.boolean().optional().describe('If true, use SSE stream variant (/mind/synthesize/stream)'),
22
+ });
23
+ exports.SYNTHESIZE_TOOL_DEF = {
24
+ name: 'tacit_synthesize',
25
+ description: 'Synthesize knowledge from the Tacit workspace. ' +
26
+ 'stream:false (default) → POST /api/v1/mind/synthesize (JSON). ' +
27
+ 'stream:true → POST /api/v1/mind/synthesize/stream (SSE; also exposed as tacit_ask / tacit_compose aliases).',
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {
31
+ query: { type: 'string', description: 'Question or synthesis prompt' },
32
+ scope: { type: 'string', description: 'Optional scope filter' },
33
+ stream: { type: 'boolean', description: 'Use SSE stream variant if true' },
34
+ },
35
+ required: ['query'],
36
+ },
37
+ };
38
+ /**
39
+ * Build a synthesize request object. Call .execute() to perform the HTTP call.
40
+ * Exported for testability (allows injecting a mock TacitClient).
41
+ */
42
+ function buildSynthesizeRequest(client, input) {
43
+ return {
44
+ async execute() {
45
+ const { query, scope, stream } = input;
46
+ const body = { query };
47
+ if (scope)
48
+ body['scope'] = scope;
49
+ try {
50
+ if (stream) {
51
+ // SSE path: POST /api/v1/mind/synthesize/stream
52
+ const chunks = [];
53
+ for await (const chunk of client.postSSE('/api/v1/mind/synthesize/stream', body)) {
54
+ chunks.push(chunk);
55
+ }
56
+ if (chunks.length === 0) {
57
+ return {
58
+ content: [{ type: 'text', text: JSON.stringify({ chunks: 0, text: '' }) }],
59
+ };
60
+ }
61
+ // Aggregate: return all chunks as content items for D7 chunk counting.
62
+ return {
63
+ content: chunks.map((c) => ({ type: 'text', text: c })),
64
+ };
65
+ }
66
+ else {
67
+ // JSON path: POST /api/v1/mind/synthesize
68
+ const result = await client.post('/api/v1/mind/synthesize', body);
69
+ return {
70
+ content: [{ type: 'text', text: JSON.stringify(result) }],
71
+ };
72
+ }
73
+ }
74
+ catch (err) {
75
+ if (err instanceof client_js_1.TacitApiError) {
76
+ return { content: [{ type: 'text', text: `API error ${err.statusCode}: ${err.body}` }], isError: true };
77
+ }
78
+ const msg = err instanceof Error ? err.message : String(err);
79
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
80
+ }
81
+ },
82
+ };
83
+ }
84
+ async function handleSynthesize(args) {
85
+ const parsed = exports.synthesizeInputSchema.safeParse(args);
86
+ if (!parsed.success) {
87
+ return {
88
+ content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }],
89
+ isError: true,
90
+ };
91
+ }
92
+ return buildSynthesizeRequest((0, client_js_1.getClient)(), parsed.data).execute();
93
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@tacitai/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "stdio MCP server wrapping Tacit /api/v1 REST/SSE API",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/scottkmcmillan/tacit.git",
9
+ "directory": "packages/tacit-mcp-server"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "main": "dist/index.js",
15
+ "bin": {
16
+ "tacit-mcp-server": "./dist/index.js"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "!dist/**/*.map"
21
+ ],
22
+ "engines": {
23
+ "node": ">=18.0.0"
24
+ },
25
+ "compatibility": {
26
+ "coreArtifact": ">=1.0.0 <2.0.0"
27
+ },
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "prepublishOnly": "npm run build",
31
+ "test": "vitest run"
32
+ },
33
+ "dependencies": {
34
+ "@modelcontextprotocol/sdk": "^1.0.0",
35
+ "semver": "^7.6.0",
36
+ "zod": "^3.22.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.0.0",
40
+ "@types/semver": "^7.5.0",
41
+ "typescript": "^5.4.0",
42
+ "vitest": "^4.1.7"
43
+ }
44
+ }