@decispher/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,219 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ export class DecispherClient {
3
+ baseUrl;
4
+ apiKey;
5
+ companyId;
6
+ sessionId;
7
+ /** Notices from the most recent envelope, surfaced by tools.ts in `_meta`. */
8
+ lastNotices = null;
9
+ constructor() {
10
+ this.baseUrl = process.env['DECISPHER_API_URL'] ?? 'http://localhost:3000';
11
+ this.apiKey = process.env['DECISPHER_API_KEY'] ?? '';
12
+ this.companyId = process.env['DECISPHER_COMPANY_ID'] ?? '';
13
+ this.sessionId = process.env['DECISPHER_SESSION_ID'] ?? randomUUID();
14
+ if (!this.apiKey || !this.companyId) {
15
+ throw new Error('DECISPHER_API_KEY and DECISPHER_COMPANY_ID environment variables are required');
16
+ }
17
+ }
18
+ async searchDecisions(query, options) {
19
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/search-decisions`, {
20
+ query,
21
+ ...(options?.limit !== undefined ? { limit: options.limit } : {}),
22
+ ...(options?.types ? { types: options.types } : {}),
23
+ });
24
+ const data = await this.unwrap(response);
25
+ return data?.results ?? [];
26
+ }
27
+ async getConstraints(options) {
28
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/get-constraints`, {
29
+ ...(options?.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),
30
+ ...(options?.cursor !== undefined ? { cursor: options.cursor } : {}),
31
+ ...(options?.expand ? { expand: options.expand } : {}),
32
+ });
33
+ const data = await this.unwrap(response);
34
+ return data?.constraints ?? [];
35
+ }
36
+ async getConventions(options) {
37
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/check-conventions`, {
38
+ ...(options?.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),
39
+ ...(options?.cursor !== undefined ? { cursor: options.cursor } : {}),
40
+ ...(options?.expand ? { expand: options.expand } : {}),
41
+ });
42
+ const data = await this.unwrap(response);
43
+ return data?.conventions ?? [];
44
+ }
45
+ async ask(query) {
46
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/ask-knowledge-base`, { query });
47
+ const data = await this.unwrap(response);
48
+ if (!data) {
49
+ const status = response.ok ? 'empty response' : `HTTP ${response.status}`;
50
+ throw new Error(`ask_knowledge_base: Decispher API unreachable or returned an error (${status}). Cannot answer from knowledge base.`);
51
+ }
52
+ return data;
53
+ }
54
+ async getDecision(decisionId) {
55
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/get-decision`, { decisionId });
56
+ const data = await this.unwrap(response);
57
+ if (!data) {
58
+ const status = response.ok ? 'empty response' : `HTTP ${response.status}`;
59
+ throw new Error(`get_decision: Decispher API returned an error (${status}) for decision ${decisionId}.`);
60
+ }
61
+ return data;
62
+ }
63
+ async checkIntent(description, files) {
64
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/check-intent`, { description, files });
65
+ const data = await this.unwrap(response);
66
+ if (!data) {
67
+ const status = response.ok ? 'empty response' : `HTTP ${response.status}`;
68
+ throw new Error(`check_intent: Decispher API unreachable or returned an error (${status}). Cannot verify intent — do not proceed without manual review.`);
69
+ }
70
+ return data;
71
+ }
72
+ async getContextForFiles(files, options) {
73
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/get-context-for-file`, {
74
+ files: files.map((f) => ({
75
+ filePath: f.filePath,
76
+ ...(f.fileContent !== undefined ? { fileContent: f.fileContent } : {}),
77
+ ...(f.language !== undefined ? { language: f.language } : {}),
78
+ })),
79
+ ...(options?.limit !== undefined ? { limit: options.limit } : {}),
80
+ });
81
+ const data = await this.unwrap(response);
82
+ return data?.matches ?? [];
83
+ }
84
+ async getContextForFile(filePath, options) {
85
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/get-context-for-file`, {
86
+ filePath,
87
+ ...(options?.fileContent !== undefined ? { fileContent: options.fileContent } : {}),
88
+ ...(options?.language !== undefined ? { language: options.language } : {}),
89
+ ...(options?.limit !== undefined ? { limit: options.limit } : {}),
90
+ });
91
+ const data = await this.unwrap(response);
92
+ return data?.matches ?? [];
93
+ }
94
+ async listTopics() {
95
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/list-topics`, {});
96
+ const data = await this.unwrap(response);
97
+ return data?.topics ?? [];
98
+ }
99
+ async getContextForTopic(topic, options) {
100
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/get-context-for-topic`, {
101
+ topic,
102
+ ...(options?.includeBodies !== undefined ? { includeBodies: options.includeBodies } : {}),
103
+ ...(options?.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),
104
+ });
105
+ if (response.status === 404) {
106
+ throw new Error(`get_context_for_topic: topic "${topic}" not found in this project's scope. Call list_topics for the available set.`);
107
+ }
108
+ const data = await this.unwrap(response);
109
+ if (!data) {
110
+ const status = response.ok ? 'empty response' : `HTTP ${response.status}`;
111
+ throw new Error(`get_context_for_topic: Decispher API returned an error (${status}).`);
112
+ }
113
+ return data;
114
+ }
115
+ async captureDecision(input) {
116
+ const response = await this.post(`/api/companies/${this.companyId}/mcp/capture-decision`, input);
117
+ if (response.status === 403) {
118
+ throw new Error('capture_decision: agent capture is disabled by the company administrator.');
119
+ }
120
+ if (response.status === 429) {
121
+ const retryAfterMs = Number(response.headers.get('retry-after-ms') ?? '0');
122
+ throw new Error(`capture_decision: rate limit exceeded — retry in ~${Math.ceil(retryAfterMs / 1000)}s.`);
123
+ }
124
+ const data = await this.unwrap(response);
125
+ if (!data) {
126
+ const status = response.ok ? 'empty response' : `HTTP ${response.status}`;
127
+ throw new Error(`capture_decision: Decispher API returned an error (${status}).`);
128
+ }
129
+ return data;
130
+ }
131
+ /**
132
+ * Probe `/api/mcp/health` before the first tool call — no auth required.
133
+ * Returns null on any network/parse failure so the caller can fall through
134
+ * to the static tool list instead of crashing the MCP server at startup.
135
+ */
136
+ async fetchHealth() {
137
+ try {
138
+ const response = await fetch(`${this.baseUrl}/api/mcp/health`, { method: 'GET' });
139
+ if (!response.ok)
140
+ return null;
141
+ return (await response.json());
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ }
147
+ /**
148
+ * Pull the tool registry from the server. Returns null if the request fails
149
+ * or the response shape is unrecognised — caller falls back to the embedded
150
+ * static tool list so the MCP server still works offline / against an older
151
+ * API that does not yet expose `/capabilities`.
152
+ */
153
+ async fetchCapabilities() {
154
+ try {
155
+ const response = await fetch(`${this.baseUrl}/api/companies/${this.companyId}/mcp/capabilities`, { method: 'GET', headers: this.headers() });
156
+ if (!response.ok)
157
+ return null;
158
+ const parsed = (await response.json());
159
+ if (!parsed || !Array.isArray(parsed.tools) || !parsed.apiKey || typeof parsed.apiVersion !== 'string') {
160
+ return null;
161
+ }
162
+ return parsed;
163
+ }
164
+ catch {
165
+ return null;
166
+ }
167
+ }
168
+ /** Parse an MCP envelope; transparently passes through legacy un-wrapped responses. */
169
+ async unwrap(response) {
170
+ if (!response.ok) {
171
+ this.lastNotices = null;
172
+ return null;
173
+ }
174
+ let parsed;
175
+ try {
176
+ parsed = await response.json();
177
+ }
178
+ catch {
179
+ this.lastNotices = null;
180
+ return null;
181
+ }
182
+ if (this.isEnvelope(parsed)) {
183
+ this.lastNotices = {
184
+ truncated: parsed.budget?.truncated ?? false,
185
+ citationCount: parsed.citations?.length ?? 0,
186
+ };
187
+ return (parsed.data ?? null);
188
+ }
189
+ this.lastNotices = null;
190
+ return parsed;
191
+ }
192
+ isEnvelope(value) {
193
+ if (typeof value !== 'object' || value === null)
194
+ return false;
195
+ const v = value;
196
+ return 'data' in v && 'meta' in v && 'budget' in v;
197
+ }
198
+ async post(path, body) {
199
+ try {
200
+ return await fetch(`${this.baseUrl}${path}`, {
201
+ method: 'POST',
202
+ headers: this.headers(),
203
+ body: JSON.stringify(body),
204
+ });
205
+ }
206
+ catch (err) {
207
+ const msg = err instanceof Error ? err.message : String(err);
208
+ throw new Error(`Decispher API unreachable at ${this.baseUrl} — ${msg}`);
209
+ }
210
+ }
211
+ headers() {
212
+ return {
213
+ 'Content-Type': 'application/json',
214
+ 'x-api-key': this.apiKey,
215
+ 'x-decispher-session-id': this.sessionId,
216
+ };
217
+ }
218
+ }
219
+ //# sourceMappingURL=decispher-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decispher-client.js","sourceRoot":"","sources":["../src/decispher-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { DecispherClient } from './decispher-client.js';
5
+ import { registerTools } from './tools.js';
6
+ async function resolveRegistration(client) {
7
+ const caps = await client.fetchCapabilities();
8
+ if (!caps) {
9
+ process.stderr.write('Decispher MCP: /capabilities unreachable — registering embedded tool list.\n');
10
+ return {};
11
+ }
12
+ const enabledTools = new Set(caps.tools.map((t) => t.name));
13
+ const descriptions = Object.fromEntries(caps.tools.map((t) => [t.name, t.description]));
14
+ process.stderr.write(`Decispher MCP: loaded ${caps.tools.length} tools from /capabilities (apiVersion=${caps.apiVersion}).\n`);
15
+ return { enabledTools, descriptions };
16
+ }
17
+ async function main() {
18
+ const client = new DecispherClient();
19
+ const server = new McpServer({
20
+ name: 'decispher',
21
+ version: '0.1.0',
22
+ });
23
+ const options = await resolveRegistration(client);
24
+ registerTools(server, client, options);
25
+ const transport = new StdioServerTransport();
26
+ await server.connect(transport);
27
+ }
28
+ main().catch((error) => {
29
+ process.stderr.write(`Decispher MCP server error: ${String(error)}\n`);
30
+ process.exit(1);
31
+ });
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAA6B,MAAM,YAAY,CAAC;AAEtE,KAAK,UAAU,mBAAmB,CAAC,MAAuB;IACtD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;IAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,8EAA8E,CACjF,CAAC;QACF,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,yBAAyB,IAAI,CAAC,KAAK,CAAC,MAAM,yCAAyC,IAAI,CAAC,UAAU,MAAM,CAC3G,CAAC;IACF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AAC1C,CAAC;AAED,KAAK,UAAU,IAAI;IACf,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IAErC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QACzB,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;KACnB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAClD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAEvC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * WS-F — Client-side file reader for `get_context_for_file`.
3
+ *
4
+ * Reads the file from the developer's disk before calling the API so the
5
+ * server can embed the actual source (not just the path). Cap at 256 KB;
6
+ * over-cap files are sliced head-then-tail and flagged `truncated: true` so
7
+ * the server-side `FileSkeletonBuilder` (tree-sitter / regex extractors,
8
+ * WS-A) still has a representative chunk to extract symbols from.
9
+ *
10
+ * Binary files and unreadable paths return `null` — the caller passes only
11
+ * the path and the API falls back to path-only embedding (the legacy
12
+ * behaviour). We never throw out of this module: a bad file read should
13
+ * degrade gracefully, not surface as an MCP tool error to the agent.
14
+ */
15
+ export declare const DEFAULT_FILE_READ_MAX_BYTES: number;
16
+ export interface FileReadResult {
17
+ readonly content: string;
18
+ readonly language: string | null;
19
+ readonly truncated: boolean;
20
+ readonly bytesRead: number;
21
+ }
22
+ export interface FileReadOptions {
23
+ readonly maxBytes?: number;
24
+ /** Override the working directory used for resolving relative paths. */
25
+ readonly cwd?: string;
26
+ }
27
+ export declare function detectLanguage(filePath: string): string | null;
28
+ export declare function readFileForContext(filePath: string, opts?: FileReadOptions): Promise<FileReadResult | null>;
29
+ //# sourceMappingURL=file-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-reader.d.ts","sourceRoot":"","sources":["../../src/lib/file-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,eAAO,MAAM,2BAA2B,QAAa,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACzB;AAmCD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9D;AAiBD,wBAAsB,kBAAkB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,eAAoB,GAC3B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA4DhC"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * WS-F — Client-side file reader for `get_context_for_file`.
3
+ *
4
+ * Reads the file from the developer's disk before calling the API so the
5
+ * server can embed the actual source (not just the path). Cap at 256 KB;
6
+ * over-cap files are sliced head-then-tail and flagged `truncated: true` so
7
+ * the server-side `FileSkeletonBuilder` (tree-sitter / regex extractors,
8
+ * WS-A) still has a representative chunk to extract symbols from.
9
+ *
10
+ * Binary files and unreadable paths return `null` — the caller passes only
11
+ * the path and the API falls back to path-only embedding (the legacy
12
+ * behaviour). We never throw out of this module: a bad file read should
13
+ * degrade gracefully, not surface as an MCP tool error to the agent.
14
+ */
15
+ import { promises as fs } from 'node:fs';
16
+ import { resolve, extname } from 'node:path';
17
+ export const DEFAULT_FILE_READ_MAX_BYTES = 256 * 1024;
18
+ const TRUNCATION_MARKER = '\n\n/* … truncated by MCP file-reader … */\n\n';
19
+ const TRUNCATION_MARKER_BYTES = Buffer.byteLength(TRUNCATION_MARKER, 'utf8');
20
+ const HEAD_FRACTION = 0.75;
21
+ const UTF8_BOM = '';
22
+ // Extension → language tag understood by tree-sitter-wasms on the server.
23
+ // Anything unknown returns null and the server falls back to regex extractors.
24
+ const EXTENSION_TO_LANGUAGE = {
25
+ '.ts': 'typescript',
26
+ '.tsx': 'tsx',
27
+ '.cts': 'typescript',
28
+ '.mts': 'typescript',
29
+ '.js': 'javascript',
30
+ '.jsx': 'javascript',
31
+ '.cjs': 'javascript',
32
+ '.mjs': 'javascript',
33
+ '.py': 'python',
34
+ '.pyi': 'python',
35
+ '.go': 'go',
36
+ '.rs': 'rust',
37
+ '.java': 'java',
38
+ '.rb': 'ruby',
39
+ '.php': 'php',
40
+ '.cs': 'csharp',
41
+ '.kt': 'kotlin',
42
+ '.swift': 'swift',
43
+ '.c': 'c',
44
+ '.h': 'c',
45
+ '.cc': 'cpp',
46
+ '.cpp': 'cpp',
47
+ '.hpp': 'cpp',
48
+ };
49
+ export function detectLanguage(filePath) {
50
+ return EXTENSION_TO_LANGUAGE[extname(filePath).toLowerCase()] ?? null;
51
+ }
52
+ function looksBinary(sample) {
53
+ // Heuristic identical to git's: a NUL byte anywhere in the first 8 KB
54
+ // means it's binary. Catches images / archives / compiled binaries
55
+ // without misclassifying UTF-8 source code with multi-byte runes.
56
+ const probeLength = Math.min(sample.length, 8 * 1024);
57
+ for (let i = 0; i < probeLength; i++) {
58
+ if (sample[i] === 0x00)
59
+ return true;
60
+ }
61
+ return false;
62
+ }
63
+ function stripBom(text) {
64
+ return text.startsWith(UTF8_BOM) ? text.slice(UTF8_BOM.length) : text;
65
+ }
66
+ export async function readFileForContext(filePath, opts = {}) {
67
+ const maxBytes = opts.maxBytes ?? DEFAULT_FILE_READ_MAX_BYTES;
68
+ const absolute = resolve(opts.cwd ?? process.cwd(), filePath);
69
+ let stat;
70
+ try {
71
+ stat = await fs.stat(absolute);
72
+ }
73
+ catch {
74
+ return null;
75
+ }
76
+ if (!stat.isFile())
77
+ return null;
78
+ const size = stat.size;
79
+ const language = detectLanguage(filePath);
80
+ let handle;
81
+ try {
82
+ handle = await fs.open(absolute, 'r');
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ try {
88
+ if (size <= maxBytes) {
89
+ const buf = Buffer.alloc(size);
90
+ await handle.read(buf, 0, size, 0);
91
+ if (looksBinary(buf))
92
+ return null;
93
+ return {
94
+ content: stripBom(buf.toString('utf8')),
95
+ language,
96
+ truncated: false,
97
+ bytesRead: size,
98
+ };
99
+ }
100
+ // Reserve room for the marker so the emitted string stays ≤ maxBytes —
101
+ // the server route caps fileContent at exactly 256 KB and rejects more.
102
+ const budget = Math.max(maxBytes - TRUNCATION_MARKER_BYTES, 0);
103
+ const headBytes = Math.floor(budget * HEAD_FRACTION);
104
+ const tailBytes = budget - headBytes;
105
+ const head = Buffer.alloc(headBytes);
106
+ await handle.read(head, 0, headBytes, 0);
107
+ if (looksBinary(head))
108
+ return null;
109
+ const tail = Buffer.alloc(tailBytes);
110
+ await handle.read(tail, 0, tailBytes, size - tailBytes);
111
+ const content = stripBom(head.toString('utf8')) + TRUNCATION_MARKER + tail.toString('utf8');
112
+ return {
113
+ content,
114
+ language,
115
+ truncated: true,
116
+ bytesRead: Buffer.byteLength(content, 'utf8'),
117
+ };
118
+ }
119
+ catch {
120
+ return null;
121
+ }
122
+ finally {
123
+ await handle.close().catch(() => { });
124
+ }
125
+ }
126
+ //# sourceMappingURL=file-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-reader.js","sourceRoot":"","sources":["../../src/lib/file-reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { type ZodTypeAny } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import type { DecispherClient } from './decispher-client.js';
4
+ declare function buildResult(text: string, client: DecispherClient, extraMeta?: Record<string, unknown>): {
5
+ _meta?: Record<string, unknown> | undefined;
6
+ content: {
7
+ type: "text";
8
+ text: string;
9
+ }[];
10
+ };
11
+ type ToolHandler = (args: Record<string, unknown>, client: DecispherClient) => Promise<ReturnType<typeof buildResult>>;
12
+ interface ToolDefinition {
13
+ readonly name: string;
14
+ readonly defaultDescription: string;
15
+ readonly inputSchema: Record<string, ZodTypeAny>;
16
+ readonly handler: ToolHandler;
17
+ }
18
+ /**
19
+ * Tool definitions — input schemas + handlers live here because the wire
20
+ * protocol with the MCP runtime is typed via Zod and the call body shapes
21
+ * are code-defined. Descriptions can be overridden at registration time by
22
+ * the server's /capabilities response (WS-E) so docs and gating live in
23
+ * one place server-side, but the executable bits stay client-side.
24
+ */
25
+ export declare const TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
26
+ export interface RegisterToolsOptions {
27
+ /**
28
+ * Filter to tools the server's /capabilities response advertised. When
29
+ * provided, any tool whose name isn't in this list is skipped. When
30
+ * omitted, all known tools are registered (offline-safe fallback).
31
+ */
32
+ readonly enabledTools?: ReadonlySet<string>;
33
+ /**
34
+ * Per-tool description override — server's /capabilities response wins so
35
+ * the agent sees the canonical copy maintained server-side.
36
+ */
37
+ readonly descriptions?: Readonly<Record<string, string>>;
38
+ }
39
+ export declare function registerTools(server: McpServer, client: DecispherClient, options?: RegisterToolsOptions): void;
40
+ export {};
41
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EACR,eAAe,EAElB,MAAM,uBAAuB,CAAC;AAQ/B,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;EAgB9F;AAED,KAAK,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC;AAEvH,UAAU,cAAc;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CACjC;AAwDD;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,cAAc,CAuP1D,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5C;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED,wBAAgB,aAAa,CACzB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,oBAAyB,GACnC,IAAI,CAiBN"}