kernl 0.1.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.
- package/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +53 -0
- package/LICENSE +201 -0
- package/dist/agent.d.ts +43 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +130 -0
- package/dist/context.d.ts +70 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +111 -0
- package/dist/env.d.ts +45 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +31 -0
- package/dist/error.d.ts +1 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +1 -0
- package/dist/guardrail.d.ts +178 -0
- package/dist/guardrail.d.ts.map +1 -0
- package/dist/guardrail.js +34 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/kernel.d.ts +7 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +7 -0
- package/dist/kernl.d.ts +18 -0
- package/dist/kernl.d.ts.map +1 -0
- package/dist/kernl.js +16 -0
- package/dist/lib/env.d.ts +43 -0
- package/dist/lib/env.d.ts.map +1 -0
- package/dist/lib/env.js +29 -0
- package/dist/lib/error.d.ts +88 -0
- package/dist/lib/error.d.ts.map +1 -0
- package/dist/lib/error.js +117 -0
- package/dist/lib/logger.d.ts +36 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +43 -0
- package/dist/lib/serde/__tests__/codec.test.d.ts +2 -0
- package/dist/lib/serde/__tests__/codec.test.d.ts.map +1 -0
- package/dist/lib/serde/__tests__/codec.test.js +75 -0
- package/dist/lib/serde/codec.d.ts +12 -0
- package/dist/lib/serde/codec.d.ts.map +1 -0
- package/dist/lib/serde/codec.js +54 -0
- package/dist/lib/serde/json.d.ts +8 -0
- package/dist/lib/serde/json.d.ts.map +1 -0
- package/dist/lib/serde/json.js +13 -0
- package/dist/lib/serde/thread.d.ts +1 -0
- package/dist/lib/serde/thread.d.ts.map +1 -0
- package/dist/lib/serde/thread.js +172 -0
- package/dist/lib/serde/tool.d.ts +36 -0
- package/dist/lib/serde/tool.d.ts.map +1 -0
- package/dist/lib/serde/tool.js +1 -0
- package/dist/lib/utils.d.ts +19 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +41 -0
- package/dist/lifecycle.d.ts +133 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +29 -0
- package/dist/logger.d.ts +36 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +43 -0
- package/dist/mcp/__tests__/base.test.d.ts +2 -0
- package/dist/mcp/__tests__/base.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/base.test.js +268 -0
- package/dist/mcp/__tests__/fixtures/echo-server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/echo-server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/echo-server.js +92 -0
- package/dist/mcp/__tests__/fixtures/math-server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/math-server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/math-server.js +98 -0
- package/dist/mcp/__tests__/fixtures/server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/server.js +162 -0
- package/dist/mcp/__tests__/fixtures/test-server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/test-server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/test-server.js +163 -0
- package/dist/mcp/__tests__/fixtures/utils.d.ts +17 -0
- package/dist/mcp/__tests__/fixtures/utils.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/utils.js +42 -0
- package/dist/mcp/__tests__/integration.test.d.ts +2 -0
- package/dist/mcp/__tests__/integration.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/integration.test.js +360 -0
- package/dist/mcp/__tests__/stdio.test.d.ts +2 -0
- package/dist/mcp/__tests__/stdio.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/stdio.test.js +180 -0
- package/dist/mcp/__tests__/test-utils.d.ts +17 -0
- package/dist/mcp/__tests__/test-utils.d.ts.map +1 -0
- package/dist/mcp/__tests__/test-utils.js +42 -0
- package/dist/mcp/__tests__/utils.test.d.ts +2 -0
- package/dist/mcp/__tests__/utils.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/utils.test.js +300 -0
- package/dist/mcp/base.d.ts +88 -0
- package/dist/mcp/base.d.ts.map +1 -0
- package/dist/mcp/base.js +68 -0
- package/dist/mcp/http.d.ts +34 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/http.js +100 -0
- package/dist/mcp/node.d.ts +60 -0
- package/dist/mcp/node.d.ts.map +1 -0
- package/dist/mcp/node.js +297 -0
- package/dist/mcp/sse.d.ts +34 -0
- package/dist/mcp/sse.d.ts.map +1 -0
- package/dist/mcp/sse.js +97 -0
- package/dist/mcp/stdio.d.ts +32 -0
- package/dist/mcp/stdio.d.ts.map +1 -0
- package/dist/mcp/stdio.js +96 -0
- package/dist/mcp/types.d.ts +172 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +16 -0
- package/dist/mcp/utils.d.ts +23 -0
- package/dist/mcp/utils.d.ts.map +1 -0
- package/dist/mcp/utils.js +44 -0
- package/dist/model.d.ts +175 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +1 -0
- package/dist/providers/ai.d.ts +1 -0
- package/dist/providers/ai.d.ts.map +1 -0
- package/dist/providers/ai.js +1 -0
- package/dist/providers/default.d.ts +16 -0
- package/dist/providers/default.d.ts.map +1 -0
- package/dist/providers/default.js +17 -0
- package/dist/providers/registry.d.ts +1 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +1 -0
- package/dist/sched/scheduler.d.ts +20 -0
- package/dist/sched/scheduler.d.ts.map +1 -0
- package/dist/sched/scheduler.js +1 -0
- package/dist/sched/task.d.ts +92 -0
- package/dist/sched/task.d.ts.map +1 -0
- package/dist/sched/task.js +102 -0
- package/dist/serde/__tests__/codec.test.d.ts +2 -0
- package/dist/serde/__tests__/codec.test.d.ts.map +1 -0
- package/dist/serde/__tests__/codec.test.js +75 -0
- package/dist/serde/codec.d.ts +12 -0
- package/dist/serde/codec.d.ts.map +1 -0
- package/dist/serde/codec.js +54 -0
- package/dist/serde/json.d.ts +8 -0
- package/dist/serde/json.d.ts.map +1 -0
- package/dist/serde/json.js +13 -0
- package/dist/serde/thread.d.ts +687 -0
- package/dist/serde/thread.d.ts.map +1 -0
- package/dist/serde/thread.js +158 -0
- package/dist/serde/tool.d.ts +36 -0
- package/dist/serde/tool.d.ts.map +1 -0
- package/dist/serde/tool.js +1 -0
- package/dist/session.d.ts +1 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +1 -0
- package/dist/task.d.ts +87 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +97 -0
- package/dist/thread/__tests__/mock.d.ts +28 -0
- package/dist/thread/__tests__/mock.d.ts.map +1 -0
- package/dist/thread/__tests__/mock.js +74 -0
- package/dist/thread/__tests__/thread.test.d.ts +2 -0
- package/dist/thread/__tests__/thread.test.d.ts.map +1 -0
- package/dist/thread/__tests__/thread.test.js +1412 -0
- package/dist/thread/index.d.ts +2 -0
- package/dist/thread/index.d.ts.map +1 -0
- package/dist/thread/index.js +1 -0
- package/dist/thread/thread.d.ts +66 -0
- package/dist/thread/thread.d.ts.map +1 -0
- package/dist/thread/thread.js +472 -0
- package/dist/thread/utils.d.ts +19 -0
- package/dist/thread/utils.d.ts.map +1 -0
- package/dist/thread/utils.js +50 -0
- package/dist/tool/__tests__/fixtures.d.ts +45 -0
- package/dist/tool/__tests__/fixtures.d.ts.map +1 -0
- package/dist/tool/__tests__/fixtures.js +97 -0
- package/dist/tool/__tests__/tool.test.d.ts +2 -0
- package/dist/tool/__tests__/tool.test.d.ts.map +1 -0
- package/dist/tool/__tests__/tool.test.js +172 -0
- package/dist/tool/__tests__/toolkit.test.d.ts +2 -0
- package/dist/tool/__tests__/toolkit.test.d.ts.map +1 -0
- package/dist/tool/__tests__/toolkit.test.js +134 -0
- package/dist/tool/index.d.ts +4 -0
- package/dist/tool/index.d.ts.map +1 -0
- package/dist/tool/index.js +2 -0
- package/dist/tool/mcp.d.ts +75 -0
- package/dist/tool/mcp.d.ts.map +1 -0
- package/dist/tool/mcp.js +111 -0
- package/dist/tool/tool.d.ts +95 -0
- package/dist/tool/tool.d.ts.map +1 -0
- package/dist/tool/tool.js +176 -0
- package/dist/tool/toolkit.d.ts +121 -0
- package/dist/tool/toolkit.d.ts.map +1 -0
- package/dist/tool/toolkit.js +180 -0
- package/dist/tool/types.d.ts +187 -0
- package/dist/tool/types.d.ts.map +1 -0
- package/dist/tool/types.js +1 -0
- package/dist/tools.d.ts +362 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +220 -0
- package/dist/trace/processor.d.ts +1 -0
- package/dist/trace/processor.d.ts.map +1 -0
- package/dist/trace/processor.js +1 -0
- package/dist/trace/traces.d.ts +1 -0
- package/dist/trace/traces.d.ts.map +1 -0
- package/dist/trace/traces.js +73 -0
- package/dist/trace/utils.d.ts +22 -0
- package/dist/trace/utils.d.ts.map +1 -0
- package/dist/trace/utils.js +30 -0
- package/dist/types/agent.d.ts +91 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +1 -0
- package/dist/types/proto.d.ts +1551 -0
- package/dist/types/proto.d.ts.map +1 -0
- package/dist/types/proto.js +531 -0
- package/dist/types/thread.d.ts +71 -0
- package/dist/types/thread.d.ts.map +1 -0
- package/dist/types/thread.js +5 -0
- package/dist/usage.d.ts +43 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +61 -0
- package/package.json +52 -0
- package/src/agent.ts +203 -0
- package/src/context.ts +265 -0
- package/src/guardrail.ts +277 -0
- package/src/index.ts +3 -0
- package/src/kernl.ts +22 -0
- package/src/lib/env.ts +36 -0
- package/src/lib/error.ts +158 -0
- package/src/lib/logger.ts +78 -0
- package/src/lib/serde/json.ts +18 -0
- package/src/lib/serde/thread.ts +188 -0
- package/src/lifecycle.ts +181 -0
- package/src/mcp/__tests__/base.test.ts +344 -0
- package/src/mcp/__tests__/fixtures/server.ts +179 -0
- package/src/mcp/__tests__/fixtures/utils.ts +58 -0
- package/src/mcp/__tests__/integration.test.ts +447 -0
- package/src/mcp/__tests__/stdio.test.ts +236 -0
- package/src/mcp/__tests__/utils.test.ts +360 -0
- package/src/mcp/base.ts +162 -0
- package/src/mcp/http.ts +147 -0
- package/src/mcp/sse.ts +137 -0
- package/src/mcp/stdio.ts +136 -0
- package/src/mcp/types.ts +202 -0
- package/src/mcp/utils.ts +62 -0
- package/src/task.ts +119 -0
- package/src/thread/__tests__/mock.ts +95 -0
- package/src/thread/__tests__/thread.test.ts +1574 -0
- package/src/thread/index.ts +1 -0
- package/src/thread/thread.ts +611 -0
- package/src/thread/utils.ts +67 -0
- package/src/tool/__tests__/fixtures.ts +106 -0
- package/src/tool/__tests__/tool.test.ts +235 -0
- package/src/tool/__tests__/toolkit.test.ts +174 -0
- package/src/tool/index.ts +10 -0
- package/src/tool/tool.ts +264 -0
- package/src/tool/toolkit.ts +234 -0
- package/src/tool/types.ts +243 -0
- package/src/trace/processor.ts +0 -0
- package/src/trace/traces.ts +86 -0
- package/src/trace/utils.ts +38 -0
- package/src/types/agent.ts +145 -0
- package/src/types/thread.ts +86 -0
- package/tsconfig.json +13 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
/**
|
|
3
|
+
* Generic typed event emitter that wraps Node's EventEmitter with type safety
|
|
4
|
+
*/
|
|
5
|
+
class TypedEventEmitter extends EventEmitter {
|
|
6
|
+
on(event, listener) {
|
|
7
|
+
return super.on(event, listener);
|
|
8
|
+
}
|
|
9
|
+
off(event, listener) {
|
|
10
|
+
return super.off(event, listener);
|
|
11
|
+
}
|
|
12
|
+
emit(event, ...args) {
|
|
13
|
+
return super.emit(event, ...args);
|
|
14
|
+
}
|
|
15
|
+
once(event, listener) {
|
|
16
|
+
return super.once(event, listener);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Event emitter that every Agent instance inherits from and that emits events for the lifecycle
|
|
21
|
+
* of the agent.
|
|
22
|
+
*/
|
|
23
|
+
export class AgentHooks extends TypedEventEmitter {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Event emitter that the kernl uses to emit events for the lifecycle of every agent run.
|
|
27
|
+
*/
|
|
28
|
+
export class KernlHooks extends TypedEventEmitter {
|
|
29
|
+
}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A logger instance with namespace support and sensitive data flags.
|
|
3
|
+
*/
|
|
4
|
+
export type Logger = {
|
|
5
|
+
/**
|
|
6
|
+
* The namespace used for the logger.
|
|
7
|
+
*/
|
|
8
|
+
namespace: string;
|
|
9
|
+
trace: (message: any, ...args: any[]) => void;
|
|
10
|
+
debug: (message: any, ...args: any[]) => void;
|
|
11
|
+
info: (message: any, ...args: any[]) => void;
|
|
12
|
+
warn: (message: any, ...args: any[]) => void;
|
|
13
|
+
error: (message: any, ...args: any[]) => void;
|
|
14
|
+
fatal: (message: any, ...args: any[]) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Whether to log model data.
|
|
17
|
+
*/
|
|
18
|
+
dontLogModelData: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Whether to log tool data.
|
|
21
|
+
*/
|
|
22
|
+
dontLogToolData: boolean;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Get a logger for a given namespace.
|
|
26
|
+
*
|
|
27
|
+
* @param namespace - the namespace to use for the logger (e.g., 'kernl:core', 'kernl:agent').
|
|
28
|
+
* @returns A logger object with all pino log levels and sensitive data flags.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getLogger(namespace?: string): Logger;
|
|
31
|
+
/**
|
|
32
|
+
* Default logger instance for the core library.
|
|
33
|
+
*/
|
|
34
|
+
export declare const logger: Logger;
|
|
35
|
+
export default logger;
|
|
36
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG;IACnB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC9C,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC9C,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC7C,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC7C,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC9C,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAE9C;;OAEG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,SAAS,GAAE,MAAgB,GAAG,MAAM,CAc7D;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,QAA0B,CAAC;AAE9C,eAAe,MAAM,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import pino from "pino";
|
|
2
|
+
import { env } from "./env";
|
|
3
|
+
/**
|
|
4
|
+
* By default we don't log LLM inputs/outputs, to prevent exposing sensitive data.
|
|
5
|
+
* Set KERNL_LOG_MODEL_DATA=true to enable.
|
|
6
|
+
*/
|
|
7
|
+
const dontLogModelData = !env.KERNL_LOG_MODEL_DATA;
|
|
8
|
+
/**
|
|
9
|
+
* By default we don't log tool inputs/outputs, to prevent exposing sensitive data.
|
|
10
|
+
* Set KERNL_LOG_TOOL_DATA=true to enable.
|
|
11
|
+
*/
|
|
12
|
+
const dontLogToolData = !env.KERNL_LOG_TOOL_DATA;
|
|
13
|
+
/**
|
|
14
|
+
* Base pino logger instance
|
|
15
|
+
*/
|
|
16
|
+
const base = pino({
|
|
17
|
+
level: env.LOG_LEVEL,
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Get a logger for a given namespace.
|
|
21
|
+
*
|
|
22
|
+
* @param namespace - the namespace to use for the logger (e.g., 'kernl:core', 'kernl:agent').
|
|
23
|
+
* @returns A logger object with all pino log levels and sensitive data flags.
|
|
24
|
+
*/
|
|
25
|
+
export function getLogger(namespace = "kernl") {
|
|
26
|
+
const child = base.child({ namespace });
|
|
27
|
+
return {
|
|
28
|
+
namespace,
|
|
29
|
+
trace: child.trace.bind(child),
|
|
30
|
+
debug: child.debug.bind(child),
|
|
31
|
+
info: child.info.bind(child),
|
|
32
|
+
warn: child.warn.bind(child),
|
|
33
|
+
error: child.error.bind(child),
|
|
34
|
+
fatal: child.fatal.bind(child),
|
|
35
|
+
dontLogModelData,
|
|
36
|
+
dontLogToolData,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Default logger instance for the core library.
|
|
41
|
+
*/
|
|
42
|
+
export const logger = getLogger("kernl:core");
|
|
43
|
+
export default logger;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.test.d.ts","sourceRoot":"","sources":["../../../src/mcp/__tests__/base.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { BaseMCPServer } from "../base";
|
|
3
|
+
import { logger } from "../../lib/logger";
|
|
4
|
+
// Create a minimal concrete implementation for testing
|
|
5
|
+
class TestMCPServer extends BaseMCPServer {
|
|
6
|
+
id;
|
|
7
|
+
mockTools = [];
|
|
8
|
+
isConnected = false;
|
|
9
|
+
constructor(id, options) {
|
|
10
|
+
super({
|
|
11
|
+
cacheToolsList: options?.cacheToolsList,
|
|
12
|
+
toolFilter: options?.toolFilter,
|
|
13
|
+
logger: logger,
|
|
14
|
+
});
|
|
15
|
+
this.id = id;
|
|
16
|
+
}
|
|
17
|
+
// Method to set mock tools for testing
|
|
18
|
+
setMockTools(tools) {
|
|
19
|
+
this.mockTools = tools;
|
|
20
|
+
}
|
|
21
|
+
async connect() {
|
|
22
|
+
this.isConnected = true;
|
|
23
|
+
}
|
|
24
|
+
async close() {
|
|
25
|
+
this.isConnected = false;
|
|
26
|
+
}
|
|
27
|
+
async _listTools() {
|
|
28
|
+
if (!this.isConnected) {
|
|
29
|
+
throw new Error("Not connected");
|
|
30
|
+
}
|
|
31
|
+
return this.mockTools;
|
|
32
|
+
}
|
|
33
|
+
async callTool(toolName, args) {
|
|
34
|
+
if (!this.isConnected) {
|
|
35
|
+
throw new Error("Not connected");
|
|
36
|
+
}
|
|
37
|
+
return [{ type: "text", text: `Called ${toolName}` }];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
describe("BaseMCPServer", () => {
|
|
41
|
+
describe("Caching mechanisms", () => {
|
|
42
|
+
it("should have cache disabled by default", () => {
|
|
43
|
+
const server = new TestMCPServer("test-server");
|
|
44
|
+
expect(server.cacheToolsList).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
it("should store tools correctly when cache enabled", async () => {
|
|
47
|
+
const server = new TestMCPServer("test-server", {
|
|
48
|
+
cacheToolsList: true,
|
|
49
|
+
});
|
|
50
|
+
const mockTools = [
|
|
51
|
+
{
|
|
52
|
+
name: "tool1",
|
|
53
|
+
description: "First tool",
|
|
54
|
+
inputSchema: { type: "object", properties: {} },
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "tool2",
|
|
58
|
+
description: "Second tool",
|
|
59
|
+
inputSchema: { type: "object", properties: {} },
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
server.setMockTools(mockTools);
|
|
63
|
+
await server.connect();
|
|
64
|
+
const tools = await server.listTools();
|
|
65
|
+
expect(tools).toEqual(mockTools);
|
|
66
|
+
expect(tools).toHaveLength(2);
|
|
67
|
+
});
|
|
68
|
+
it("should return same reference on subsequent calls when cached", async () => {
|
|
69
|
+
const server = new TestMCPServer("test-server", {
|
|
70
|
+
cacheToolsList: true,
|
|
71
|
+
});
|
|
72
|
+
const mockTools = [
|
|
73
|
+
{
|
|
74
|
+
name: "tool1",
|
|
75
|
+
inputSchema: { type: "object", properties: {} },
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
server.setMockTools(mockTools);
|
|
79
|
+
await server.connect();
|
|
80
|
+
const tools1 = await server.listTools();
|
|
81
|
+
const tools2 = await server.listTools();
|
|
82
|
+
// Should return the exact same cached reference
|
|
83
|
+
expect(tools1).toBe(tools2);
|
|
84
|
+
});
|
|
85
|
+
it("should fetch fresh tools when cache disabled", async () => {
|
|
86
|
+
const server = new TestMCPServer("test-server", {
|
|
87
|
+
cacheToolsList: false,
|
|
88
|
+
});
|
|
89
|
+
const mockTools = [
|
|
90
|
+
{
|
|
91
|
+
name: "tool1",
|
|
92
|
+
inputSchema: { type: "object", properties: {} },
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
server.setMockTools(mockTools);
|
|
96
|
+
await server.connect();
|
|
97
|
+
const tools1 = await server.listTools();
|
|
98
|
+
const tools2 = await server.listTools();
|
|
99
|
+
// Both should succeed and have correct data
|
|
100
|
+
expect(tools1).toEqual(mockTools);
|
|
101
|
+
expect(tools2).toEqual(mockTools);
|
|
102
|
+
});
|
|
103
|
+
it("should have cache isolated per server instance", async () => {
|
|
104
|
+
const server1 = new TestMCPServer("server1", {
|
|
105
|
+
cacheToolsList: true,
|
|
106
|
+
});
|
|
107
|
+
const server2 = new TestMCPServer("server2", {
|
|
108
|
+
cacheToolsList: true,
|
|
109
|
+
});
|
|
110
|
+
const tools1 = [
|
|
111
|
+
{
|
|
112
|
+
name: "tool1",
|
|
113
|
+
inputSchema: { type: "object", properties: {} },
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
const tools2 = [
|
|
117
|
+
{
|
|
118
|
+
name: "tool2",
|
|
119
|
+
inputSchema: { type: "object", properties: {} },
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
server1.setMockTools(tools1);
|
|
123
|
+
server2.setMockTools(tools2);
|
|
124
|
+
await server1.connect();
|
|
125
|
+
await server2.connect();
|
|
126
|
+
const result1 = await server1.listTools();
|
|
127
|
+
const result2 = await server2.listTools();
|
|
128
|
+
expect(result1).toEqual(tools1);
|
|
129
|
+
expect(result2).toEqual(tools2);
|
|
130
|
+
expect(result1).not.toEqual(result2);
|
|
131
|
+
});
|
|
132
|
+
it("should clear cache when invalidateCache() called", async () => {
|
|
133
|
+
const server = new TestMCPServer("test-server", {
|
|
134
|
+
cacheToolsList: true,
|
|
135
|
+
});
|
|
136
|
+
const initialTools = [
|
|
137
|
+
{
|
|
138
|
+
name: "tool1",
|
|
139
|
+
inputSchema: { type: "object", properties: {} },
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
server.setMockTools(initialTools);
|
|
143
|
+
await server.connect();
|
|
144
|
+
// First fetch - populates cache
|
|
145
|
+
await server.listTools();
|
|
146
|
+
// Invalidate cache
|
|
147
|
+
await server.invalidateCache();
|
|
148
|
+
// Update mock tools
|
|
149
|
+
const newTools = [
|
|
150
|
+
{
|
|
151
|
+
name: "tool2",
|
|
152
|
+
inputSchema: { type: "object", properties: {} },
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
server.setMockTools(newTools);
|
|
156
|
+
// Next fetch should get new tools, not cached ones
|
|
157
|
+
const result = await server.listTools();
|
|
158
|
+
expect(result).toEqual(newTools);
|
|
159
|
+
});
|
|
160
|
+
it("should set _cacheDirty flag when invalidateCache() called", async () => {
|
|
161
|
+
const server = new TestMCPServer("test-server", {
|
|
162
|
+
cacheToolsList: true,
|
|
163
|
+
});
|
|
164
|
+
await server.connect();
|
|
165
|
+
server.setMockTools([
|
|
166
|
+
{ name: "tool1", inputSchema: { type: "object", properties: {} } },
|
|
167
|
+
]);
|
|
168
|
+
// Populate cache
|
|
169
|
+
await server.listTools();
|
|
170
|
+
// Invalidate
|
|
171
|
+
await server.invalidateCache();
|
|
172
|
+
// The next listTools() call should fetch fresh data
|
|
173
|
+
// We can verify this by changing the mock tools and seeing the change
|
|
174
|
+
server.setMockTools([
|
|
175
|
+
{ name: "tool2", inputSchema: { type: "object", properties: {} } },
|
|
176
|
+
]);
|
|
177
|
+
const tools = await server.listTools();
|
|
178
|
+
expect(tools[0].name).toBe("tool2");
|
|
179
|
+
});
|
|
180
|
+
it("should skip cache when _cacheDirty is true", async () => {
|
|
181
|
+
const server = new TestMCPServer("test-server", {
|
|
182
|
+
cacheToolsList: true,
|
|
183
|
+
});
|
|
184
|
+
await server.connect();
|
|
185
|
+
// First call
|
|
186
|
+
server.setMockTools([
|
|
187
|
+
{ name: "tool1", inputSchema: { type: "object", properties: {} } },
|
|
188
|
+
]);
|
|
189
|
+
await server.listTools();
|
|
190
|
+
// Invalidate cache (sets _cacheDirty = true)
|
|
191
|
+
await server.invalidateCache();
|
|
192
|
+
// Change mock tools
|
|
193
|
+
server.setMockTools([
|
|
194
|
+
{ name: "tool2", inputSchema: { type: "object", properties: {} } },
|
|
195
|
+
]);
|
|
196
|
+
// Should fetch fresh tools, not use cache
|
|
197
|
+
const tools = await server.listTools();
|
|
198
|
+
expect(tools[0].name).toBe("tool2");
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe("Abstract class contracts", () => {
|
|
202
|
+
it("should allow subclass to implement connect()", async () => {
|
|
203
|
+
const server = new TestMCPServer("test-server");
|
|
204
|
+
await expect(server.connect()).resolves.not.toThrow();
|
|
205
|
+
});
|
|
206
|
+
it("should allow subclass to implement close()", async () => {
|
|
207
|
+
const server = new TestMCPServer("test-server");
|
|
208
|
+
await server.connect();
|
|
209
|
+
await expect(server.close()).resolves.not.toThrow();
|
|
210
|
+
});
|
|
211
|
+
it("should allow subclass to implement _listTools()", async () => {
|
|
212
|
+
const server = new TestMCPServer("test-server");
|
|
213
|
+
server.setMockTools([
|
|
214
|
+
{ name: "tool1", inputSchema: { type: "object", properties: {} } },
|
|
215
|
+
]);
|
|
216
|
+
await server.connect();
|
|
217
|
+
const tools = await server.listTools();
|
|
218
|
+
expect(tools).toHaveLength(1);
|
|
219
|
+
expect(tools[0].name).toBe("tool1");
|
|
220
|
+
});
|
|
221
|
+
it("should allow subclass to implement callTool()", async () => {
|
|
222
|
+
const server = new TestMCPServer("test-server");
|
|
223
|
+
await server.connect();
|
|
224
|
+
const result = await server.callTool("test_tool", { arg: "value" });
|
|
225
|
+
expect(result).toHaveLength(1);
|
|
226
|
+
expect(result[0].text).toContain("test_tool");
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
describe("toolFilter integration", () => {
|
|
230
|
+
it("should default to allow-all filter", async () => {
|
|
231
|
+
const server = new TestMCPServer("test-server");
|
|
232
|
+
// The default filter should allow all tools
|
|
233
|
+
expect(server.toolFilter).toBeDefined();
|
|
234
|
+
// Test that it returns true for any tool
|
|
235
|
+
const mockContext = {
|
|
236
|
+
context: {},
|
|
237
|
+
agent: {},
|
|
238
|
+
serverId: "test",
|
|
239
|
+
};
|
|
240
|
+
const mockTool = {
|
|
241
|
+
name: "any_tool",
|
|
242
|
+
inputSchema: { type: "object", properties: {} },
|
|
243
|
+
};
|
|
244
|
+
const result = await server.toolFilter(mockContext, mockTool);
|
|
245
|
+
expect(result).toBe(true);
|
|
246
|
+
});
|
|
247
|
+
it("should store custom filter correctly in constructor", async () => {
|
|
248
|
+
const customFilter = vi.fn().mockResolvedValue(false);
|
|
249
|
+
const server = new TestMCPServer("test-server", {
|
|
250
|
+
toolFilter: customFilter,
|
|
251
|
+
});
|
|
252
|
+
expect(server.toolFilter).toBe(customFilter);
|
|
253
|
+
// Verify the filter is actually used
|
|
254
|
+
const mockContext = {
|
|
255
|
+
context: {},
|
|
256
|
+
agent: {},
|
|
257
|
+
serverId: "test",
|
|
258
|
+
};
|
|
259
|
+
const mockTool = {
|
|
260
|
+
name: "tool1",
|
|
261
|
+
inputSchema: { type: "object", properties: {} },
|
|
262
|
+
};
|
|
263
|
+
const result = await server.toolFilter(mockContext, mockTool);
|
|
264
|
+
expect(result).toBe(false);
|
|
265
|
+
expect(customFilter).toHaveBeenCalledWith(mockContext, mockTool);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"echo-server.d.ts","sourceRoot":"","sources":["../../../../src/mcp/__tests__/fixtures/echo-server.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Simple echo/string manipulation server for testing MCP stdio transport.
|
|
4
|
+
*
|
|
5
|
+
* Provides deterministic string transformations.
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
const server = new Server({
|
|
10
|
+
name: "echo-server",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
}, {
|
|
13
|
+
capabilities: {
|
|
14
|
+
tools: {},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
// List available tools
|
|
18
|
+
server.setRequestHandler("tools/list", async () => ({
|
|
19
|
+
tools: [
|
|
20
|
+
{
|
|
21
|
+
name: "echo",
|
|
22
|
+
description: "Echo back the input text",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
text: { type: "string", description: "Text to echo" },
|
|
27
|
+
},
|
|
28
|
+
required: ["text"],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "uppercase",
|
|
33
|
+
description: "Convert text to uppercase",
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
text: { type: "string", description: "Text to convert" },
|
|
38
|
+
},
|
|
39
|
+
required: ["text"],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "reverse",
|
|
44
|
+
description: "Reverse the text",
|
|
45
|
+
inputSchema: {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: {
|
|
48
|
+
text: { type: "string", description: "Text to reverse" },
|
|
49
|
+
},
|
|
50
|
+
required: ["text"],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
}));
|
|
55
|
+
// Handle tool calls
|
|
56
|
+
server.setRequestHandler("tools/call", async (request) => {
|
|
57
|
+
const { name, arguments: args } = request.params;
|
|
58
|
+
switch (name) {
|
|
59
|
+
case "echo":
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: "text",
|
|
64
|
+
text: args.text,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
case "uppercase":
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: args.text.toUpperCase(),
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
case "reverse":
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: args.text.split("").reverse().join(""),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
default:
|
|
87
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Start the server
|
|
91
|
+
const transport = new StdioServerTransport();
|
|
92
|
+
await server.connect(transport);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math-server.d.ts","sourceRoot":"","sources":["../../../../src/mcp/__tests__/fixtures/math-server.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Simple deterministic math server for testing MCP stdio transport.
|
|
4
|
+
*
|
|
5
|
+
* Provides basic arithmetic operations with predictable results.
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
const server = new Server({
|
|
10
|
+
name: "math-server",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
}, {
|
|
13
|
+
capabilities: {
|
|
14
|
+
tools: {},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
// List available tools
|
|
18
|
+
server.setRequestHandler("tools/list", async () => ({
|
|
19
|
+
tools: [
|
|
20
|
+
{
|
|
21
|
+
name: "add",
|
|
22
|
+
description: "Add two numbers",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
a: { type: "number", description: "First number" },
|
|
27
|
+
b: { type: "number", description: "Second number" },
|
|
28
|
+
},
|
|
29
|
+
required: ["a", "b"],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "multiply",
|
|
34
|
+
description: "Multiply two numbers",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
a: { type: "number", description: "First number" },
|
|
39
|
+
b: { type: "number", description: "Second number" },
|
|
40
|
+
},
|
|
41
|
+
required: ["a", "b"],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "divide",
|
|
46
|
+
description: "Divide two numbers",
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
a: { type: "number", description: "Numerator" },
|
|
51
|
+
b: { type: "number", description: "Denominator" },
|
|
52
|
+
},
|
|
53
|
+
required: ["a", "b"],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
}));
|
|
58
|
+
// Handle tool calls
|
|
59
|
+
server.setRequestHandler("tools/call", async (request) => {
|
|
60
|
+
const { name, arguments: args } = request.params;
|
|
61
|
+
switch (name) {
|
|
62
|
+
case "add":
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: "text",
|
|
67
|
+
text: String(args.a + args.b),
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
case "multiply":
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: "text",
|
|
76
|
+
text: String(args.a * args.b),
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
case "divide":
|
|
81
|
+
if (args.b === 0) {
|
|
82
|
+
throw new Error("Division by zero");
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: "text",
|
|
88
|
+
text: String(args.a / args.b),
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
default:
|
|
93
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// Start the server
|
|
97
|
+
const transport = new StdioServerTransport();
|
|
98
|
+
await server.connect(transport);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/mcp/__tests__/fixtures/server.ts"],"names":[],"mappings":""}
|