@ganintegrity/mcp 1.0.0 → 1.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/README.md +191 -84
- package/dist/{als.d.ts → core/als.d.ts} +11 -4
- package/dist/core/als.d.ts.map +1 -0
- package/dist/core/als.js.map +1 -0
- package/dist/{auth → core/auth}/auth.types.d.ts +6 -0
- package/dist/core/auth/auth.types.d.ts.map +1 -0
- package/dist/{auth → core/auth}/auth.types.js.map +1 -1
- package/dist/core/auth/index.d.ts +34 -0
- package/dist/core/auth/index.d.ts.map +1 -0
- package/dist/core/auth/index.js +57 -0
- package/dist/core/auth/index.js.map +1 -0
- package/dist/core/define.d.ts +80 -0
- package/dist/core/define.d.ts.map +1 -0
- package/dist/core/define.js +52 -0
- package/dist/core/define.js.map +1 -0
- package/dist/core/dispatch.d.ts +35 -0
- package/dist/core/dispatch.d.ts.map +1 -0
- package/dist/core/dispatch.js +57 -0
- package/dist/core/dispatch.js.map +1 -0
- package/dist/{errors → core/errors}/errors.types.d.ts +21 -0
- package/dist/core/errors/errors.types.d.ts.map +1 -0
- package/dist/core/errors/errors.types.js.map +1 -0
- package/dist/{errors → core/errors}/index.d.ts +4 -0
- package/dist/core/errors/index.d.ts.map +1 -0
- package/dist/{errors → core/errors}/index.js +4 -0
- package/dist/core/errors/index.js.map +1 -0
- package/dist/core/test-helpers.d.ts +20 -0
- package/dist/core/test-helpers.d.ts.map +1 -0
- package/dist/core/test-helpers.js +38 -0
- package/dist/core/test-helpers.js.map +1 -0
- package/dist/core/tool/index.d.ts +19 -0
- package/dist/core/tool/index.d.ts.map +1 -0
- package/dist/{tool → core/tool}/index.js +28 -25
- package/dist/core/tool/index.js.map +1 -0
- package/dist/{tool → core/tool}/tool.types.d.ts +38 -2
- package/dist/core/tool/tool.types.d.ts.map +1 -0
- package/dist/{tool → core/tool}/tool.types.js.map +1 -1
- package/dist/{auth/index.d.ts → express/auth.d.ts} +10 -9
- package/dist/express/auth.d.ts.map +1 -0
- package/dist/express/auth.js +49 -0
- package/dist/express/auth.js.map +1 -0
- package/dist/express/express.types.d.ts +37 -0
- package/dist/express/express.types.d.ts.map +1 -0
- package/dist/express/express.types.js +2 -0
- package/dist/express/express.types.js.map +1 -0
- package/dist/express/index.d.ts +41 -0
- package/dist/express/index.d.ts.map +1 -0
- package/dist/express/index.js +59 -0
- package/dist/express/index.js.map +1 -0
- package/dist/index.d.ts +21 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/package.json +8 -1
- package/dist/als.d.ts.map +0 -1
- package/dist/als.js.map +0 -1
- package/dist/auth/auth.types.d.ts.map +0 -1
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js +0 -74
- package/dist/auth/index.js.map +0 -1
- package/dist/errors/errors.types.d.ts.map +0 -1
- package/dist/errors/errors.types.js.map +0 -1
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/server/index.d.ts +0 -18
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.js +0 -130
- package/dist/server/index.js.map +0 -1
- package/dist/server/server.types.d.ts +0 -78
- package/dist/server/server.types.d.ts.map +0 -1
- package/dist/server/server.types.js +0 -2
- package/dist/server/server.types.js.map +0 -1
- package/dist/tool/index.d.ts +0 -26
- package/dist/tool/index.d.ts.map +0 -1
- package/dist/tool/index.js.map +0 -1
- package/dist/tool/tool.types.d.ts.map +0 -1
- /package/dist/{als.js → core/als.js} +0 -0
- /package/dist/{auth → core/auth}/auth.types.js +0 -0
- /package/dist/{errors → core/errors}/errors.types.js +0 -0
- /package/dist/{tool → core/tool}/tool.types.js +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { McpErrorMapper } from "./errors/errors.types.ts";
|
|
3
|
+
import type { ToolRegister, ToolRegistration } from "./tool/tool.types.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Options for {@link defineMcpServer}.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export interface DefineMcpServerOptions {
|
|
10
|
+
/** MCP server name advertised to clients during initialisation. */
|
|
11
|
+
name: string;
|
|
12
|
+
/** MCP server version advertised to clients during initialisation. */
|
|
13
|
+
version: string;
|
|
14
|
+
/**
|
|
15
|
+
* Registration callback. Called **once at define time** with a
|
|
16
|
+
* `register` object whose `tool(spec)` method captures each tool into
|
|
17
|
+
* an internal array. Adapters replay the array onto a fresh `McpServer`
|
|
18
|
+
* per HTTP request.
|
|
19
|
+
*
|
|
20
|
+
* Don't put expensive setup in here — it's intended only for
|
|
21
|
+
* `register.tool(...)` calls.
|
|
22
|
+
*/
|
|
23
|
+
tools: (register: ToolRegister) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Translate a thrown error into an MCP envelope. Return `null` to fall
|
|
26
|
+
* through to a redacted `INTERNAL_ERROR` envelope. Without a mapper,
|
|
27
|
+
* every thrown error becomes `INTERNAL_ERROR` with the message redacted.
|
|
28
|
+
*/
|
|
29
|
+
errorMapper?: McpErrorMapper;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The serialisable shape adapters consume. Holds the captured tool
|
|
33
|
+
* registrations alongside the metadata needed to materialise an SDK server
|
|
34
|
+
* per request. Treat as opaque outside of adapters and tests.
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
export interface McpDefinition {
|
|
39
|
+
/** MCP server name, forwarded to the SDK server on each request. */
|
|
40
|
+
readonly name: string;
|
|
41
|
+
/** MCP server version, forwarded to the SDK server on each request. */
|
|
42
|
+
readonly version: string;
|
|
43
|
+
/**
|
|
44
|
+
* Captured tool registrations. Adapters pass these through to
|
|
45
|
+
* `materializeSdkServer`, which replays them onto a fresh SDK server
|
|
46
|
+
* per request. Typical consumers don't touch this; adapter authors do.
|
|
47
|
+
*/
|
|
48
|
+
readonly registrations: readonly ToolRegistration[];
|
|
49
|
+
/** Error mapper carried from the `DefineMcpServerOptions`. */
|
|
50
|
+
readonly errorMapper?: McpErrorMapper;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Define an MCP server. Returns an {@link McpDefinition} that adapters
|
|
54
|
+
* (e.g. `@ganintegrity/mcp/express`'s `createMcpRouter`) materialise into
|
|
55
|
+
* a real SDK server per request.
|
|
56
|
+
*
|
|
57
|
+
* The `tools` callback runs once, here, at define time. The `register`
|
|
58
|
+
* argument captures each `register.tool(spec)` invocation; the wrapped
|
|
59
|
+
* handler bakes in ALS-reading, transaction lifecycle, and error mapping
|
|
60
|
+
* so per-request adapters can replay the registrations onto a fresh
|
|
61
|
+
* `McpServer` without any extra wiring.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export declare function defineMcpServer(options: DefineMcpServerOptions): McpDefinition;
|
|
66
|
+
/**
|
|
67
|
+
* Build a fresh SDK `McpServer` from an {@link McpDefinition} and replay
|
|
68
|
+
* every recorded tool registration onto it.
|
|
69
|
+
*
|
|
70
|
+
* Adapters call this once per HTTP request — the SDK's stateless
|
|
71
|
+
* Streamable-HTTP transport is single-use, which is why registrations
|
|
72
|
+
* are stored separately and replayed.
|
|
73
|
+
*
|
|
74
|
+
* Exposed for tests and advanced consumers writing custom adapters.
|
|
75
|
+
* Typical consumers don't call this directly.
|
|
76
|
+
*
|
|
77
|
+
* @public
|
|
78
|
+
*/
|
|
79
|
+
export declare function materializeSdkServer(mcp: McpDefinition): McpServer;
|
|
80
|
+
//# sourceMappingURL=define.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/core/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG3E;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,KAAK,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpD,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,CAAC,EAAE,cAAc,CAAC;CACvC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,GAC9B,aAAa,CAcf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,CAiBlE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { wrapToolHandler } from "./tool/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Define an MCP server. Returns an {@link McpDefinition} that adapters
|
|
5
|
+
* (e.g. `@ganintegrity/mcp/express`'s `createMcpRouter`) materialise into
|
|
6
|
+
* a real SDK server per request.
|
|
7
|
+
*
|
|
8
|
+
* The `tools` callback runs once, here, at define time. The `register`
|
|
9
|
+
* argument captures each `register.tool(spec)` invocation; the wrapped
|
|
10
|
+
* handler bakes in ALS-reading, transaction lifecycle, and error mapping
|
|
11
|
+
* so per-request adapters can replay the registrations onto a fresh
|
|
12
|
+
* `McpServer` without any extra wiring.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export function defineMcpServer(options) {
|
|
17
|
+
const registrations = [];
|
|
18
|
+
const register = {
|
|
19
|
+
tool: (spec) => {
|
|
20
|
+
registrations.push(wrapToolHandler(spec));
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
options.tools(register);
|
|
24
|
+
return {
|
|
25
|
+
name: options.name,
|
|
26
|
+
version: options.version,
|
|
27
|
+
registrations,
|
|
28
|
+
errorMapper: options.errorMapper,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build a fresh SDK `McpServer` from an {@link McpDefinition} and replay
|
|
33
|
+
* every recorded tool registration onto it.
|
|
34
|
+
*
|
|
35
|
+
* Adapters call this once per HTTP request — the SDK's stateless
|
|
36
|
+
* Streamable-HTTP transport is single-use, which is why registrations
|
|
37
|
+
* are stored separately and replayed.
|
|
38
|
+
*
|
|
39
|
+
* Exposed for tests and advanced consumers writing custom adapters.
|
|
40
|
+
* Typical consumers don't call this directly.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export function materializeSdkServer(mcp) {
|
|
45
|
+
const server = new McpServer({ name: mcp.name, version: mcp.version });
|
|
46
|
+
const register = server.registerTool.bind(server);
|
|
47
|
+
for (const reg of mcp.registrations) {
|
|
48
|
+
register(reg.name, reg.config, reg.handler);
|
|
49
|
+
}
|
|
50
|
+
return server;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=define.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/core/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAoDlD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA+B;IAE/B,MAAM,aAAa,GAAuB,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAiB;QAC7B,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;YACb,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,CAAC;KACF,CAAC;IACF,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,aAAa;QACb,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAkB;IACrD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IASvE,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CACvC,MAAM,CACsB,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QACpC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
+
import type { Postgan } from "@ganintegrity/postgan";
|
|
3
|
+
import type { Logger } from "pino";
|
|
4
|
+
import type { AuthUser } from "./auth/auth.types.ts";
|
|
5
|
+
import { type McpDefinition } from "./define.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Per-request scope handed to {@link dispatchMcpRequest}. The framework
|
|
8
|
+
* adapter pulls these out of its native request shape (Express `req.user` /
|
|
9
|
+
* `req.postgan` / `req.mcpSessionId`; Koa `ctx.state.*`).
|
|
10
|
+
*/
|
|
11
|
+
interface DispatchScope {
|
|
12
|
+
user: AuthUser;
|
|
13
|
+
postgan: Postgan;
|
|
14
|
+
sessionId?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Framework-neutral per-request dispatcher.
|
|
18
|
+
*
|
|
19
|
+
* Builds the {@link RequestStore} from `scope` + `mcp.errorMapper`,
|
|
20
|
+
* materialises a fresh SDK `McpServer` (with all tools replayed onto it),
|
|
21
|
+
* connects a fresh transport, runs `invokeTransport` inside
|
|
22
|
+
* `requestStore.run(...)` so tool handlers can pull request context from
|
|
23
|
+
* ALS, and tears server + transport down in `finally`. A failing close is
|
|
24
|
+
* logged at warn but never re-thrown.
|
|
25
|
+
*
|
|
26
|
+
* If `invokeTransport` throws, the error is logged at error level and
|
|
27
|
+
* `onTransportError` is called so the framework adapter can write a 500
|
|
28
|
+
* onto its native response object (with whatever headers-sent guard it
|
|
29
|
+
* uses). The error is otherwise swallowed — this is the request boundary.
|
|
30
|
+
*
|
|
31
|
+
* Never throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare function dispatchMcpRequest(mcp: McpDefinition, logger: Logger, scope: DispatchScope, invokeTransport: (transport: StreamableHTTPServerTransport) => Promise<void>, onTransportError: () => void): Promise<void>;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/core/dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvE;;;;GAIG;AACH,UAAU,aAAa;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,EACpB,eAAe,EAAE,CAAC,SAAS,EAAE,6BAA6B,KAAK,OAAO,CAAC,IAAI,CAAC,EAC5E,gBAAgB,EAAE,MAAM,IAAI,GAC3B,OAAO,CAAC,IAAI,CAAC,CAmCf"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
+
import { requestStore } from "./als.js";
|
|
3
|
+
import { materializeSdkServer } from "./define.js";
|
|
4
|
+
/**
|
|
5
|
+
* Framework-neutral per-request dispatcher.
|
|
6
|
+
*
|
|
7
|
+
* Builds the {@link RequestStore} from `scope` + `mcp.errorMapper`,
|
|
8
|
+
* materialises a fresh SDK `McpServer` (with all tools replayed onto it),
|
|
9
|
+
* connects a fresh transport, runs `invokeTransport` inside
|
|
10
|
+
* `requestStore.run(...)` so tool handlers can pull request context from
|
|
11
|
+
* ALS, and tears server + transport down in `finally`. A failing close is
|
|
12
|
+
* logged at warn but never re-thrown.
|
|
13
|
+
*
|
|
14
|
+
* If `invokeTransport` throws, the error is logged at error level and
|
|
15
|
+
* `onTransportError` is called so the framework adapter can write a 500
|
|
16
|
+
* onto its native response object (with whatever headers-sent guard it
|
|
17
|
+
* uses). The error is otherwise swallowed — this is the request boundary.
|
|
18
|
+
*
|
|
19
|
+
* Never throws.
|
|
20
|
+
*/
|
|
21
|
+
export async function dispatchMcpRequest(mcp, logger, scope, invokeTransport, onTransportError) {
|
|
22
|
+
const { user, postgan, sessionId } = scope;
|
|
23
|
+
const store = {
|
|
24
|
+
user,
|
|
25
|
+
postgan,
|
|
26
|
+
sessionId,
|
|
27
|
+
logger: logger.child({
|
|
28
|
+
sessionId,
|
|
29
|
+
userId: user.id,
|
|
30
|
+
company: user.companySubdomainName,
|
|
31
|
+
}),
|
|
32
|
+
errorMapper: mcp.errorMapper,
|
|
33
|
+
};
|
|
34
|
+
const requestServer = materializeSdkServer(mcp);
|
|
35
|
+
const transport = new StreamableHTTPServerTransport({
|
|
36
|
+
sessionIdGenerator: undefined,
|
|
37
|
+
});
|
|
38
|
+
await requestServer.connect(transport);
|
|
39
|
+
await requestStore.run(store, async () => {
|
|
40
|
+
try {
|
|
41
|
+
await invokeTransport(transport);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
logger.error({ err, sessionId }, "mcp: transport.handleRequest threw");
|
|
45
|
+
onTransportError();
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await transport.close().catch((closeErr) => {
|
|
49
|
+
logger.warn({ err: closeErr }, "mcp: transport close failed");
|
|
50
|
+
});
|
|
51
|
+
await requestServer.close().catch((closeErr) => {
|
|
52
|
+
logger.warn({ err: closeErr }, "mcp: server close failed");
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/core/dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAInG,OAAO,EAAE,YAAY,EAAqB,MAAM,UAAU,CAAC;AAE3D,OAAO,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAC;AAavE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAkB,EAClB,MAAc,EACd,KAAoB,EACpB,eAA4E,EAC5E,gBAA4B;IAE5B,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC3C,MAAM,KAAK,GAAiB;QAC1B,IAAI;QACJ,OAAO;QACP,SAAS;QACT,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC;YACnB,SAAS;YACT,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,OAAO,EAAE,IAAI,CAAC,oBAAoB;SACnC,CAAC;QACF,WAAW,EAAE,GAAG,CAAC,WAAW;KAC7B,CAAC;IAEF,MAAM,aAAa,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;QAClD,kBAAkB,EAAE,SAAS;KAC9B,CAAC,CAAC;IACH,MAAM,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEvC,MAAM,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,oCAAoC,CAAC,CAAC;YACvE,gBAAgB,EAAE,CAAC;QACrB,CAAC;gBAAS,CAAC;YACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,QAAiB,EAAE,EAAE;gBAClD,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,6BAA6B,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;YACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,QAAiB,EAAE,EAAE;gBACtD,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,0BAA0B,CAAC,CAAC;YAC7D,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
|
+
/**
|
|
3
|
+
* Drives logging behaviour when a tool throws: `"warn"` logs at info level
|
|
4
|
+
* and treats the error as expected (e.g. validation rejection); `"error"`
|
|
5
|
+
* logs at error level with the original cause attached.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
2
9
|
export type McpToolErrorSeverity = "warn" | "error";
|
|
3
10
|
/**
|
|
4
11
|
* Shape returned by an {@link McpErrorMapper} to describe how a thrown error
|
|
@@ -7,6 +14,8 @@ export type McpToolErrorSeverity = "warn" | "error";
|
|
|
7
14
|
* The library does not define an error *class* — consumers throw whatever
|
|
8
15
|
* type their service already uses, and the mapper translates it into this
|
|
9
16
|
* shape at the tool boundary.
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
10
19
|
*/
|
|
11
20
|
export interface McpToolError {
|
|
12
21
|
/** Stable machine-readable code surfaced to the agent. */
|
|
@@ -24,11 +33,23 @@ export interface McpToolError {
|
|
|
24
33
|
* Translate a thrown error into an {@link McpToolError} envelope, or
|
|
25
34
|
* return `null` to fall through to the generic `INTERNAL_ERROR` envelope
|
|
26
35
|
* with a redacted message.
|
|
36
|
+
*
|
|
37
|
+
* @public
|
|
27
38
|
*/
|
|
28
39
|
export type McpErrorMapper = (err: unknown) => McpToolError | null;
|
|
40
|
+
/**
|
|
41
|
+
* Context the tool wrapper passes to `toCallToolError` when building the
|
|
42
|
+
* MCP error envelope. Consumers writing their own tool wrappers populate
|
|
43
|
+
* this from their request scope.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
29
47
|
export interface ToolErrorMeta {
|
|
48
|
+
/** Tool name — included in error logs. */
|
|
30
49
|
tool: string;
|
|
50
|
+
/** Forwarded `X-Session-Id` value if present — included in error logs. */
|
|
31
51
|
sessionId?: string;
|
|
52
|
+
/** Logger to write the error/info entry against. */
|
|
32
53
|
logger: Logger;
|
|
33
54
|
}
|
|
34
55
|
//# sourceMappingURL=errors.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.types.d.ts","sourceRoot":"","sources":["../../../src/core/errors/errors.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,YAAY,GAAG,IAAI,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;CAChB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.types.js","sourceRoot":"","sources":["../../../src/core/errors/errors.types.ts"],"names":[],"mappings":""}
|
|
@@ -3,6 +3,8 @@ import type { McpToolError, ToolErrorMeta } from "./errors.types.ts";
|
|
|
3
3
|
/**
|
|
4
4
|
* The only code the library itself emits — surfaced in the redacted
|
|
5
5
|
* envelope when a thrown error has no mapping. Consumer codes are theirs.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
6
8
|
*/
|
|
7
9
|
export declare const INTERNAL_ERROR = "INTERNAL_ERROR";
|
|
8
10
|
/**
|
|
@@ -22,6 +24,8 @@ export declare const INTERNAL_ERROR = "INTERNAL_ERROR";
|
|
|
22
24
|
* error message is **not** surfaced.
|
|
23
25
|
*
|
|
24
26
|
* Never throws (assumes `meta.logger` does not throw).
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
25
29
|
*/
|
|
26
30
|
export declare function toCallToolError(mapped: McpToolError | null, originalErr: unknown, meta: ToolErrorMeta): CallToolResult;
|
|
27
31
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAErE;;;;;GAKG;AACH,eAAO,MAAM,cAAc,mBAAmB,CAAC;AA+D/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,YAAY,GAAG,IAAI,EAC3B,WAAW,EAAE,OAAO,EACpB,IAAI,EAAE,aAAa,GAClB,cAAc,CAMhB"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The only code the library itself emits — surfaced in the redacted
|
|
3
3
|
* envelope when a thrown error has no mapping. Consumer codes are theirs.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
4
6
|
*/
|
|
5
7
|
export const INTERNAL_ERROR = "INTERNAL_ERROR";
|
|
6
8
|
function logMappedError(mapped, meta) {
|
|
@@ -67,6 +69,8 @@ function unknownErrorEnvelope(err, meta) {
|
|
|
67
69
|
* error message is **not** surfaced.
|
|
68
70
|
*
|
|
69
71
|
* Never throws (assumes `meta.logger` does not throw).
|
|
72
|
+
*
|
|
73
|
+
* @public
|
|
70
74
|
*/
|
|
71
75
|
export function toCallToolError(mapped, originalErr, meta) {
|
|
72
76
|
if (mapped) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/errors/index.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAE/C,SAAS,cAAc,CAAC,MAAoB,EAAE,IAAmB;IAC/D,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;YACE,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,EACD,iBAAiB,CAClB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,MAAM,CAAC,IAAI,CACd;YACE,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,MAAM,CAAC,OAAO;SACxB,EACD,mBAAmB,CACpB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAAoB;IAC1C,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QACjD,iBAAiB,EAAE;YACjB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvD;KACF,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAC3B,GAAY,EACZ,IAAmB;IAEnB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;QACE,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QAC3C,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,EACD,0BAA0B,CAC3B,CAAC;IACF,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE;YACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iDAAiD,EAAE;SAC1E;QACD,iBAAiB,EAAE;YACjB,IAAI,EAAE,cAAc;YACpB,OAAO;SACR;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,eAAe,CAC7B,MAA2B,EAC3B,WAAoB,EACpB,IAAmB;IAEnB,IAAI,MAAM,EAAE,CAAC;QACX,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7B,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,oBAAoB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
import type { Logger } from "pino";
|
|
3
|
+
/**
|
|
4
|
+
* A pino-shaped mock logger. `child()` returns the same logger so assertions
|
|
5
|
+
* on `logger.error` capture calls from child loggers too — required for
|
|
6
|
+
* tests that exercise code paths which child the logger before logging.
|
|
7
|
+
*/
|
|
8
|
+
export declare function makeLogger(): Logger;
|
|
9
|
+
export interface MockTransaction {
|
|
10
|
+
active: boolean;
|
|
11
|
+
begin: ReturnType<typeof vi.fn>;
|
|
12
|
+
commit: ReturnType<typeof vi.fn>;
|
|
13
|
+
rollback: ReturnType<typeof vi.fn>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Mock postgan transaction with `commit` / `rollback` flipping `active` to
|
|
17
|
+
* false to mirror real postgan behaviour.
|
|
18
|
+
*/
|
|
19
|
+
export declare function makeTransaction(): MockTransaction;
|
|
20
|
+
//# sourceMappingURL=test-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/core/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAanC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACjC,QAAQ,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,eAAe,CAYjD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
/**
|
|
3
|
+
* A pino-shaped mock logger. `child()` returns the same logger so assertions
|
|
4
|
+
* on `logger.error` capture calls from child loggers too — required for
|
|
5
|
+
* tests that exercise code paths which child the logger before logging.
|
|
6
|
+
*/
|
|
7
|
+
export function makeLogger() {
|
|
8
|
+
const logger = {
|
|
9
|
+
info: vi.fn(),
|
|
10
|
+
warn: vi.fn(),
|
|
11
|
+
error: vi.fn(),
|
|
12
|
+
debug: vi.fn(),
|
|
13
|
+
fatal: vi.fn(),
|
|
14
|
+
trace: vi.fn(),
|
|
15
|
+
};
|
|
16
|
+
// Cast through `Logger["child"]` because pino's child is generic over a
|
|
17
|
+
// custom-levels type parameter that vi.fn() can't satisfy directly.
|
|
18
|
+
logger.child = vi.fn(() => logger);
|
|
19
|
+
return logger;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Mock postgan transaction with `commit` / `rollback` flipping `active` to
|
|
23
|
+
* false to mirror real postgan behaviour.
|
|
24
|
+
*/
|
|
25
|
+
export function makeTransaction() {
|
|
26
|
+
const tx = {
|
|
27
|
+
active: true,
|
|
28
|
+
begin: vi.fn().mockResolvedValue(undefined),
|
|
29
|
+
commit: vi.fn().mockImplementation(async () => {
|
|
30
|
+
tx.active = false;
|
|
31
|
+
}),
|
|
32
|
+
rollback: vi.fn().mockImplementation(async () => {
|
|
33
|
+
tx.active = false;
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
return tx;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=test-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/core/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG5B;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAoB;QAC9B,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACb,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;QACd,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;QACd,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;QACd,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;KACf,CAAC;IACF,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,MAAgB,CAA+B,CAAC;IAC3E,OAAO,MAAgB,CAAC;AAC1B,CAAC;AASD;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,EAAE,GAAoB;QAC1B,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;QAC3C,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;YAC5C,EAAE,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,CAAC,CAAC;QACF,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;YAC9C,EAAE,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,CAAC,CAAC;KACH,CAAC;IACF,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { ToolRegistration, ToolSpec } from "./tool.types.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Wrap a {@link ToolSpec} into an SDK-shaped {@link ToolRegistration}. The
|
|
5
|
+
* wrapped handler:
|
|
6
|
+
*
|
|
7
|
+
* 1. Reads the active request scope from `requestStore` (ALS).
|
|
8
|
+
* 2. Opens a fresh `Postgan.Transaction`.
|
|
9
|
+
* 3. Builds a {@link ToolContext} and invokes the consumer's handler.
|
|
10
|
+
* 4. Commits on resolve and returns a `CallToolResult` carrying the result
|
|
11
|
+
* as both a JSON `text` block and `structuredContent`.
|
|
12
|
+
* 5. On throw: rolls back the transaction and routes the error through the
|
|
13
|
+
* request store's `errorMapper` to build an error envelope.
|
|
14
|
+
*
|
|
15
|
+
* Internal — `defineMcpServer`'s `register.tool(spec)` calls this and
|
|
16
|
+
* pushes the result onto the definition's registration array.
|
|
17
|
+
*/
|
|
18
|
+
export declare function wrapToolHandler<Schema extends z.ZodObject, Output extends Record<string, unknown>>(spec: ToolSpec<Schema, Output>): ToolRegistration;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tool/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAI7B,OAAO,KAAK,EAAe,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AA6B/E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,MAAM,SAAS,CAAC,CAAC,SAAS,EAC1B,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtC,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,gBAAgB,CA0DlD"}
|
|
@@ -24,35 +24,25 @@ async function withTransaction(postgan, logger, body) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* Wrap a {@link ToolSpec} into an SDK-shaped {@link ToolRegistration}. The
|
|
28
|
+
* wrapped handler:
|
|
29
29
|
*
|
|
30
|
-
* 1.
|
|
31
|
-
* 2. Opens a fresh `Postgan.Transaction
|
|
32
|
-
* 3.
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* the consumer's `McpErrorMapper` (passed to `createMcpServer`) to
|
|
38
|
-
* build an MCP error envelope.
|
|
30
|
+
* 1. Reads the active request scope from `requestStore` (ALS).
|
|
31
|
+
* 2. Opens a fresh `Postgan.Transaction`.
|
|
32
|
+
* 3. Builds a {@link ToolContext} and invokes the consumer's handler.
|
|
33
|
+
* 4. Commits on resolve and returns a `CallToolResult` carrying the result
|
|
34
|
+
* as both a JSON `text` block and `structuredContent`.
|
|
35
|
+
* 5. On throw: rolls back the transaction and routes the error through the
|
|
36
|
+
* request store's `errorMapper` to build an error envelope.
|
|
39
37
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* active request scope, which indicates a programming bug (the handler was
|
|
43
|
-
* dispatched without going through `mount()`'s ALS wrapper). Such throws
|
|
44
|
-
* propagate to the SDK transport and surface as an HTTP 500. Errors raised
|
|
45
|
-
* by your own handler logic are caught and never propagate.
|
|
38
|
+
* Internal — `defineMcpServer`'s `register.tool(spec)` calls this and
|
|
39
|
+
* pushes the result onto the definition's registration array.
|
|
46
40
|
*/
|
|
47
|
-
export function
|
|
48
|
-
|
|
49
|
-
description: spec.description,
|
|
50
|
-
inputSchema: spec.inputSchema.shape,
|
|
51
|
-
...(spec.annotations ? { annotations: spec.annotations } : {}),
|
|
52
|
-
}, async (args, extra) => {
|
|
41
|
+
export function wrapToolHandler(spec) {
|
|
42
|
+
const handler = async (args, extra) => {
|
|
53
43
|
const store = requestStore.getStore();
|
|
54
44
|
if (!store) {
|
|
55
|
-
// Unreachable:
|
|
45
|
+
// Unreachable in practice: adapters always wrap dispatch in
|
|
56
46
|
// requestStore.run(). Throw to surface the bug rather than silently
|
|
57
47
|
// returning an error envelope without a logger.
|
|
58
48
|
throw new Error("mcp tool invoked outside request scope");
|
|
@@ -83,6 +73,19 @@ export function tool(server, spec) {
|
|
|
83
73
|
logger,
|
|
84
74
|
});
|
|
85
75
|
}
|
|
86
|
-
}
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
name: spec.name,
|
|
79
|
+
config: {
|
|
80
|
+
description: spec.description,
|
|
81
|
+
inputSchema: spec.inputSchema.shape,
|
|
82
|
+
...(spec.annotations ? { annotations: spec.annotations } : {}),
|
|
83
|
+
},
|
|
84
|
+
// Cast: ToolRegistration intentionally uses loose types because the
|
|
85
|
+
// SDK's `registerTool` is generically overloaded; the cast at this
|
|
86
|
+
// boundary lets the wrapped handler's specific signature flow through
|
|
87
|
+
// unchanged at the SDK call site in `materializeSdkServer`.
|
|
88
|
+
handler: handler,
|
|
89
|
+
};
|
|
87
90
|
}
|
|
88
91
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/tool/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@ import type { z } from "zod";
|
|
|
4
4
|
import type { AuthUser } from "../auth/auth.types.ts";
|
|
5
5
|
/**
|
|
6
6
|
* What every tool handler receives as its second argument.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
7
9
|
*/
|
|
8
10
|
export interface ToolContext {
|
|
9
11
|
/** Authenticated user. Cast to your service's richer type for extra fields. */
|
|
@@ -28,6 +30,8 @@ export interface ToolContext {
|
|
|
28
30
|
*
|
|
29
31
|
* Pick honestly: `readOnlyHint: true` on a tool that mutates is worse than
|
|
30
32
|
* leaving the hint unset.
|
|
33
|
+
*
|
|
34
|
+
* @public
|
|
31
35
|
*/
|
|
32
36
|
export interface ToolAnnotations {
|
|
33
37
|
/** Human-readable display title (defaults to `name` if omitted). */
|
|
@@ -45,9 +49,11 @@ export interface ToolAnnotations {
|
|
|
45
49
|
* Specification passed to `tool()`. Defines the tool's name, description,
|
|
46
50
|
* input schema, optional annotations, and the handler that executes it.
|
|
47
51
|
*
|
|
48
|
-
* @
|
|
49
|
-
* @
|
|
52
|
+
* @typeParam Schema - Zod object schema describing the tool's input.
|
|
53
|
+
* @typeParam Output - Plain object the handler returns. Surfaced as both a JSON
|
|
50
54
|
* `text` content block and as `structuredContent`.
|
|
55
|
+
*
|
|
56
|
+
* @public
|
|
51
57
|
*/
|
|
52
58
|
export interface ToolSpec<Schema extends z.ZodObject, Output> {
|
|
53
59
|
/** Stable identifier the agent uses to invoke the tool. */
|
|
@@ -69,4 +75,34 @@ export interface ToolSpec<Schema extends z.ZodObject, Output> {
|
|
|
69
75
|
*/
|
|
70
76
|
handler: (args: z.infer<Schema>, ctx: ToolContext) => Promise<Output>;
|
|
71
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Captured tool registration held on `McpDefinition.registrations` and
|
|
80
|
+
* replayed onto a fresh SDK server by {@link materializeSdkServer}.
|
|
81
|
+
*
|
|
82
|
+
* Loose types here — the SDK's `registerTool` is generically overloaded so
|
|
83
|
+
* `Parameters<>` resolves unhelpfully; `materializeSdkServer` casts at the
|
|
84
|
+
* boundary. Typical consumers don't touch this; surfaced for adapter
|
|
85
|
+
* authors who walk `McpDefinition.registrations` directly.
|
|
86
|
+
*
|
|
87
|
+
* @public
|
|
88
|
+
*/
|
|
89
|
+
export interface ToolRegistration {
|
|
90
|
+
/** The tool's stable identifier, forwarded to `registerTool` as the first argument. */
|
|
91
|
+
name: string;
|
|
92
|
+
/** SDK-shaped registration config (description, input schema, annotations). */
|
|
93
|
+
config: object;
|
|
94
|
+
/** Pre-wrapped handler — already wired with ALS, transactions, and error mapping. */
|
|
95
|
+
handler: (...args: unknown[]) => Promise<unknown>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* What `defineMcpServer({ tools })` hands to its callback. The single
|
|
99
|
+
* `tool(spec)` method captures each registration into the underlying
|
|
100
|
+
* {@link McpDefinition}.
|
|
101
|
+
*
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export interface ToolRegister {
|
|
105
|
+
/** Capture a tool registration. Call once per tool inside the `tools` callback. */
|
|
106
|
+
tool<Schema extends z.ZodObject, Output extends Record<string, unknown>>(spec: ToolSpec<Schema, Output>): void;
|
|
107
|
+
}
|
|
72
108
|
//# sourceMappingURL=tool.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.types.d.ts","sourceRoot":"","sources":["../../../src/core/tool/tool.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,IAAI,EAAE,QAAQ,CAAC;IACf,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,WAAW,EAAE,kBAAkB,CAAC;IAChC,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mDAAmD;IACnD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,QAAQ,CAAC,MAAM,SAAS,CAAC,CAAC,SAAS,EAAE,MAAM;IAC1D,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;;;OAKG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACvE;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACnD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,mFAAmF;IACnF,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC,SAAS,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrE,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,IAAI,CAAC;CACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.types.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"tool.types.js","sourceRoot":"","sources":["../../../src/core/tool/tool.types.ts"],"names":[],"mappings":""}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { RequestHandler } from "express";
|
|
2
|
-
import type { McpAuthOptions } from "
|
|
2
|
+
import type { McpAuthOptions } from "../core/auth/auth.types.ts";
|
|
3
3
|
/**
|
|
4
4
|
* Bearer-token auth middleware for the MCP HTTP endpoint.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
* does not call `next`.
|
|
6
|
+
* Reads `Authorization: Bearer <token>`. If absent the middleware responds
|
|
7
|
+
* `401` and does not call `next`.
|
|
9
8
|
*
|
|
10
9
|
* On success it sets:
|
|
11
|
-
* - `req.user` — the resolved
|
|
10
|
+
* - `req.user` — the resolved `AuthUser` (re-export from `@ganintegrity/mcp`)
|
|
12
11
|
* - `req.headers.company` — `user.companySubdomainName` (for downstream
|
|
13
12
|
* middleware that keys off the company header)
|
|
14
13
|
* - `req.auth` — SDK-shaped `AuthInfo`, surfaced to MCP tool handlers as
|
|
@@ -21,9 +20,11 @@ import type { McpAuthOptions } from "./auth.types.ts";
|
|
|
21
20
|
* **Never throws.** All failures (missing token, `tokenToUser` rejection)
|
|
22
21
|
* are turned into `401` responses; the middleware does not call `next(err)`.
|
|
23
22
|
*
|
|
24
|
-
* Mounted automatically by
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* Mounted automatically by {@link createMcpRouter}. Exported in case you
|
|
24
|
+
* want to compose it differently (e.g. mount under a different router, or
|
|
25
|
+
* stack additional middleware).
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
27
28
|
*/
|
|
28
29
|
export declare function mcpAuth(options: McpAuthOptions): RequestHandler;
|
|
29
|
-
//# sourceMappingURL=
|
|
30
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/express/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAG/E,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAI3E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAwB/D"}
|