@j0hanz/thinkseq-mcp 2.0.0 → 2.2.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/README.md +320 -227
- package/dist/app.js +25 -6
- package/dist/appConfig/env.d.ts +3 -0
- package/dist/appConfig/env.js +9 -0
- package/dist/appConfig/runDependencies.d.ts +4 -4
- package/dist/appConfig/runDependencies.js +45 -32
- package/dist/appConfig/shutdown.js +8 -5
- package/dist/assets/logo.svg +4029 -0
- package/dist/engine/revision.js +14 -26
- package/dist/engine/thoughtQueries.js +20 -13
- package/dist/engine/thoughtStore.d.ts +1 -1
- package/dist/engine/thoughtStore.js +107 -102
- package/dist/engine.js +84 -62
- package/dist/index.js +1 -0
- package/dist/instructions.md +38 -30
- package/dist/lib/context.js +11 -3
- package/dist/lib/diagnostics.d.ts +4 -1
- package/dist/lib/diagnostics.js +1 -1
- package/dist/lib/errors.d.ts +1 -4
- package/dist/lib/errors.js +6 -5
- package/dist/lib/mcpLogging.js +25 -9
- package/dist/lib/stdioGuards.js +72 -24
- package/dist/lib/types.d.ts +3 -1
- package/dist/tools/thinkseq.d.ts +1 -1
- package/dist/tools/thinkseq.js +23 -24
- package/package.json +25 -17
- package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/app.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import process from 'node:process';
|
|
1
3
|
import { resolvePackageIdentity, resolveRunDependencies, } from './appConfig/runDependencies.js';
|
|
2
4
|
import { buildShutdownDependencies } from './appConfig/shutdown.js';
|
|
5
|
+
import { runWithContext } from './lib/context.js';
|
|
3
6
|
import { installConsoleBridge, installMcpLogging } from './lib/mcpLogging.js';
|
|
4
7
|
const toError = (value) => value instanceof Error ? value : new Error(String(value));
|
|
5
8
|
const createExit = (proc, exit) => exit ?? ((code) => proc.exit(code));
|
|
@@ -8,6 +11,19 @@ const createHandlerFor = (logError, exit) => (label) => (value) => {
|
|
|
8
11
|
logError(`thinkseq: ${label}: ${error.message}`);
|
|
9
12
|
exit(1);
|
|
10
13
|
};
|
|
14
|
+
async function getLocalIconData() {
|
|
15
|
+
try {
|
|
16
|
+
const iconPath = new URL('../assets/logo.svg', import.meta.url);
|
|
17
|
+
const buffer = await readFile(iconPath);
|
|
18
|
+
if (buffer.length > 2 * 1024 * 1024) {
|
|
19
|
+
console.warn('Warning: logo.svg is larger than 2MB');
|
|
20
|
+
}
|
|
21
|
+
return `data:image/svg+xml;base64,${buffer.toString('base64')}`;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
11
27
|
export function installProcessErrorHandlers(deps = {}) {
|
|
12
28
|
const proc = deps.processLike ?? process;
|
|
13
29
|
const logError = deps.logError ?? console.error;
|
|
@@ -20,16 +36,19 @@ export async function run(deps = {}) {
|
|
|
20
36
|
const resolved = resolveRunDependencies(deps);
|
|
21
37
|
const pkg = await resolved.readPackageJson(AbortSignal.timeout(resolved.packageReadTimeoutMs));
|
|
22
38
|
const { name, version } = resolvePackageIdentity(pkg);
|
|
23
|
-
const
|
|
39
|
+
const localIcon = await getLocalIconData();
|
|
40
|
+
const server = resolved.createServer(name, version, localIcon);
|
|
24
41
|
installMcpLogging(server);
|
|
25
42
|
const { flush: flushConsole, restore: restoreConsole } = installConsoleBridge(server);
|
|
26
43
|
process.on('exit', restoreConsole);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
44
|
+
runWithContext(() => {
|
|
45
|
+
resolved.publishLifecycleEvent({
|
|
46
|
+
type: 'lifecycle.started',
|
|
47
|
+
ts: resolved.now(),
|
|
48
|
+
});
|
|
49
|
+
}, { requestId: 'lifecycle.started' });
|
|
31
50
|
const engine = resolved.engineFactory();
|
|
32
|
-
resolved.registerTool(server, engine);
|
|
51
|
+
resolved.registerTool(server, engine, localIcon);
|
|
33
52
|
const transport = await resolved.connectServer(server);
|
|
34
53
|
flushConsole();
|
|
35
54
|
resolved.installShutdownHandlers(buildShutdownDependencies(resolved, { server, engine, transport }));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
const FALSY_ENV_VALUES = new Set(['0', 'false', 'no', 'off']);
|
|
3
|
+
function resolveIncludeTextContent() {
|
|
4
|
+
const raw = process.env.THINKSEQ_INCLUDE_TEXT_CONTENT;
|
|
5
|
+
return raw === undefined || !FALSY_ENV_VALUES.has(raw.trim().toLowerCase());
|
|
6
|
+
}
|
|
7
|
+
export const APP_ENV = {
|
|
8
|
+
INCLUDE_TEXT_CONTENT: resolveIncludeTextContent(),
|
|
9
|
+
};
|
|
@@ -8,9 +8,9 @@ export interface RunDependencies {
|
|
|
8
8
|
shutdownTimeoutMs?: number;
|
|
9
9
|
readPackageJson?: (signal?: AbortSignal) => Promise<PackageInfo>;
|
|
10
10
|
publishLifecycleEvent?: (event: LifecycleEvent) => void;
|
|
11
|
-
createServer?: (name: string, version: string) => ServerLike;
|
|
11
|
+
createServer?: (name: string, version: string, icon?: string) => ServerLike;
|
|
12
12
|
connectServer?: (server: ServerLike, createTransport?: () => TransportLike) => Promise<TransportLike>;
|
|
13
|
-
registerTool?: (server: ServerLike, engine: EngineLike) => void;
|
|
13
|
+
registerTool?: (server: ServerLike, engine: EngineLike, icon?: string) => void;
|
|
14
14
|
engineFactory?: () => EngineLike;
|
|
15
15
|
installShutdownHandlers?: (deps: ShutdownDependencies) => void;
|
|
16
16
|
now?: () => number;
|
|
@@ -21,9 +21,9 @@ export interface ResolvedRunDependencies {
|
|
|
21
21
|
shutdownTimeoutMs?: number;
|
|
22
22
|
readPackageJson: (signal?: AbortSignal) => Promise<PackageInfo>;
|
|
23
23
|
publishLifecycleEvent: (event: LifecycleEvent) => void;
|
|
24
|
-
createServer: (name: string, version: string) => ServerLike;
|
|
24
|
+
createServer: (name: string, version: string, icon?: string) => ServerLike;
|
|
25
25
|
connectServer: (server: ServerLike, createTransport?: () => TransportLike) => Promise<TransportLike>;
|
|
26
|
-
registerTool: (server: ServerLike, engine: EngineLike) => void;
|
|
26
|
+
registerTool: (server: ServerLike, engine: EngineLike, icon?: string) => void;
|
|
27
27
|
engineFactory: () => EngineLike;
|
|
28
28
|
installShutdownHandlers: (deps: ShutdownDependencies) => void;
|
|
29
29
|
now: () => number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { McpServer, ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { ThinkingEngine } from '../engine.js';
|
|
@@ -9,55 +9,68 @@ import { registerThinkSeq } from '../tools/thinkseq.js';
|
|
|
9
9
|
import { installShutdownHandlers } from './shutdown.js';
|
|
10
10
|
const INSTRUCTIONS_URL = new URL('../instructions.md', import.meta.url);
|
|
11
11
|
const INSTRUCTIONS_FALLBACK = 'ThinkSeq is a tool for structured, sequential thinking with revision support.';
|
|
12
|
-
function readInstructionsText() {
|
|
12
|
+
async function readInstructionsText() {
|
|
13
13
|
try {
|
|
14
|
-
return
|
|
14
|
+
return await readFile(INSTRUCTIONS_URL, { encoding: 'utf8' });
|
|
15
15
|
}
|
|
16
16
|
catch {
|
|
17
17
|
return INSTRUCTIONS_FALLBACK;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
function loadServerInstructions() {
|
|
21
|
-
const raw = readInstructionsText();
|
|
20
|
+
function loadServerInstructions(raw) {
|
|
22
21
|
const trimmed = raw.trim();
|
|
23
22
|
return trimmed.length > 0 ? trimmed : INSTRUCTIONS_FALLBACK;
|
|
24
23
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
resources: [
|
|
29
|
-
{
|
|
30
|
-
uri: 'internal://instructions',
|
|
31
|
-
name: 'Instructions',
|
|
32
|
-
mimeType: 'text/markdown',
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
}),
|
|
36
|
-
}), { title: 'Instructions', mimeType: 'text/markdown' }, (uri) => ({
|
|
37
|
-
contents: [
|
|
24
|
+
const INSTRUCTIONS_RESOURCE_TEMPLATE = new ResourceTemplate('internal://instructions', {
|
|
25
|
+
list: () => ({
|
|
26
|
+
resources: [
|
|
38
27
|
{
|
|
39
|
-
uri:
|
|
40
|
-
|
|
28
|
+
uri: 'internal://instructions',
|
|
29
|
+
name: 'Instructions',
|
|
41
30
|
mimeType: 'text/markdown',
|
|
42
31
|
},
|
|
43
32
|
],
|
|
44
|
-
})
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
const INSTRUCTIONS_METADATA = {
|
|
36
|
+
title: 'Instructions',
|
|
37
|
+
mimeType: 'text/markdown',
|
|
38
|
+
};
|
|
39
|
+
const readInstructionsResource = (uri) => ({
|
|
40
|
+
contents: [
|
|
41
|
+
{
|
|
42
|
+
uri: uri.href,
|
|
43
|
+
text: INSTRUCTIONS_TEXT,
|
|
44
|
+
mimeType: 'text/markdown',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
function registerInstructionsResource(server) {
|
|
49
|
+
server.registerResource('instructions', INSTRUCTIONS_RESOURCE_TEMPLATE, INSTRUCTIONS_METADATA, readInstructionsResource);
|
|
45
50
|
}
|
|
46
|
-
const
|
|
51
|
+
const INSTRUCTIONS_TEXT = await readInstructionsText();
|
|
52
|
+
const SERVER_INSTRUCTIONS = loadServerInstructions(INSTRUCTIONS_TEXT);
|
|
47
53
|
const DEFAULT_PACKAGE_READ_TIMEOUT_MS = 2000;
|
|
48
|
-
function
|
|
54
|
+
function buildServerCapabilities(overrides = {}) {
|
|
49
55
|
return {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
prompts: { listChanged: false },
|
|
56
|
-
},
|
|
56
|
+
logging: {},
|
|
57
|
+
tools: { listChanged: false },
|
|
58
|
+
resources: { subscribe: false, listChanged: false },
|
|
59
|
+
prompts: { listChanged: false },
|
|
60
|
+
...overrides,
|
|
57
61
|
};
|
|
58
62
|
}
|
|
59
|
-
const defaultCreateServer = (name, version) => {
|
|
60
|
-
const
|
|
63
|
+
const defaultCreateServer = (name, version, icon) => {
|
|
64
|
+
const capabilities = buildServerCapabilities();
|
|
65
|
+
const server = new McpServer({ name, version }, {
|
|
66
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
67
|
+
capabilities,
|
|
68
|
+
...(icon
|
|
69
|
+
? {
|
|
70
|
+
icons: [{ src: icon, mimeType: 'image/svg+xml', sizes: ['any'] }],
|
|
71
|
+
}
|
|
72
|
+
: {}),
|
|
73
|
+
});
|
|
61
74
|
registerInstructionsResource(server);
|
|
62
75
|
server.registerPrompt('get-help', {
|
|
63
76
|
description: 'Get usage instructions for this server',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runWithContext } from '../lib/context.js';
|
|
1
2
|
import { publishLifecycleEvent } from '../lib/diagnostics.js';
|
|
2
3
|
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 5000;
|
|
3
4
|
function isRecord(value) {
|
|
@@ -35,11 +36,13 @@ function buildShutdownRunner(deps, proc) {
|
|
|
35
36
|
if (shuttingDown)
|
|
36
37
|
return;
|
|
37
38
|
shuttingDown = true;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
runWithContext(() => {
|
|
40
|
+
emit({
|
|
41
|
+
type: 'lifecycle.shutdown',
|
|
42
|
+
ts: timestamp(),
|
|
43
|
+
signal,
|
|
44
|
+
});
|
|
45
|
+
}, { requestId: `lifecycle.shutdown:${signal}` });
|
|
43
46
|
await closeAllWithinTimeout([deps.server, deps.engine, deps.transport], timeoutMs);
|
|
44
47
|
proc.exit(0);
|
|
45
48
|
};
|