@ganintegrity/mcp 1.0.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.
Files changed (42) hide show
  1. package/README.md +375 -0
  2. package/dist/als.d.ts +24 -0
  3. package/dist/als.d.ts.map +1 -0
  4. package/dist/als.js +3 -0
  5. package/dist/als.js.map +1 -0
  6. package/dist/auth/auth.types.d.ts +29 -0
  7. package/dist/auth/auth.types.d.ts.map +1 -0
  8. package/dist/auth/auth.types.js +2 -0
  9. package/dist/auth/auth.types.js.map +1 -0
  10. package/dist/auth/index.d.ts +29 -0
  11. package/dist/auth/index.d.ts.map +1 -0
  12. package/dist/auth/index.js +74 -0
  13. package/dist/auth/index.js.map +1 -0
  14. package/dist/errors/errors.types.d.ts +34 -0
  15. package/dist/errors/errors.types.d.ts.map +1 -0
  16. package/dist/errors/errors.types.js +2 -0
  17. package/dist/errors/errors.types.js.map +1 -0
  18. package/dist/errors/index.d.ts +27 -0
  19. package/dist/errors/index.d.ts.map +1 -0
  20. package/dist/errors/index.js +78 -0
  21. package/dist/errors/index.js.map +1 -0
  22. package/dist/index.d.ts +20 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +5 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/server/index.d.ts +18 -0
  27. package/dist/server/index.d.ts.map +1 -0
  28. package/dist/server/index.js +130 -0
  29. package/dist/server/index.js.map +1 -0
  30. package/dist/server/server.types.d.ts +78 -0
  31. package/dist/server/server.types.d.ts.map +1 -0
  32. package/dist/server/server.types.js +2 -0
  33. package/dist/server/server.types.js.map +1 -0
  34. package/dist/tool/index.d.ts +26 -0
  35. package/dist/tool/index.d.ts.map +1 -0
  36. package/dist/tool/index.js +88 -0
  37. package/dist/tool/index.js.map +1 -0
  38. package/dist/tool/tool.types.d.ts +72 -0
  39. package/dist/tool/tool.types.d.ts.map +1 -0
  40. package/dist/tool/tool.types.js +2 -0
  41. package/dist/tool/tool.types.js.map +1 -0
  42. package/package.json +65 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The only code the library itself emits — surfaced in the redacted
3
+ * envelope when a thrown error has no mapping. Consumer codes are theirs.
4
+ */
5
+ export const INTERNAL_ERROR = "INTERNAL_ERROR";
6
+ function logMappedError(mapped, meta) {
7
+ if (mapped.severity === "error") {
8
+ meta.logger.error({
9
+ cause: mapped.cause,
10
+ code: mapped.code,
11
+ tool: meta.tool,
12
+ sessionId: meta.sessionId,
13
+ }, "mcp tool failed");
14
+ }
15
+ else {
16
+ meta.logger.info({
17
+ code: mapped.code,
18
+ tool: meta.tool,
19
+ sessionId: meta.sessionId,
20
+ message: mapped.message,
21
+ }, "mcp tool rejected");
22
+ }
23
+ }
24
+ function mappedEnvelope(mapped) {
25
+ return {
26
+ isError: true,
27
+ content: [{ type: "text", text: mapped.message }],
28
+ structuredContent: {
29
+ code: mapped.code,
30
+ message: mapped.message,
31
+ ...(mapped.details ? { details: mapped.details } : {}),
32
+ },
33
+ };
34
+ }
35
+ function unknownErrorEnvelope(err, meta) {
36
+ const message = err instanceof Error ? err.message : String(err);
37
+ meta.logger.error({
38
+ err: err instanceof Error ? err : undefined,
39
+ tool: meta.tool,
40
+ sessionId: meta.sessionId,
41
+ }, "mcp tool unhandled error");
42
+ return {
43
+ isError: true,
44
+ content: [
45
+ { type: "text", text: "An unexpected error occurred. Please try again." },
46
+ ],
47
+ structuredContent: {
48
+ code: INTERNAL_ERROR,
49
+ message,
50
+ },
51
+ };
52
+ }
53
+ /**
54
+ * Build the MCP `CallToolResult` envelope for a thrown error. Called
55
+ * automatically by `tool()` after the consumer's {@link McpErrorMapper}
56
+ * has had a chance to translate the throwable. Exported for consumers
57
+ * writing their own tool wrappers.
58
+ *
59
+ * Behaviour:
60
+ * - `mapped` non-null with `severity: "warn"` → logged at info; envelope
61
+ * carries the mapped `code`/`message`/`details`. The agent sees the
62
+ * message so it can react.
63
+ * - `mapped` non-null with `severity: "error"` → logged at error (with
64
+ * `cause`); envelope carries the mapped `code`/`message`/`details`.
65
+ * - `mapped` null → logged at error with the original throwable; envelope
66
+ * is a generic `INTERNAL_ERROR` with a redacted message. The original
67
+ * error message is **not** surfaced.
68
+ *
69
+ * Never throws (assumes `meta.logger` does not throw).
70
+ */
71
+ export function toCallToolError(mapped, originalErr, meta) {
72
+ if (mapped) {
73
+ logMappedError(mapped, meta);
74
+ return mappedEnvelope(mapped);
75
+ }
76
+ return unknownErrorEnvelope(originalErr, meta);
77
+ }
78
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAGA;;;GAGG;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;;;;;;;;;;;;;;;;;GAiBG;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 type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
2
+ declare global {
3
+ namespace Express {
4
+ interface Request {
5
+ mcpSessionId?: string;
6
+ auth?: AuthInfo;
7
+ }
8
+ }
9
+ }
10
+ export { createMcpServer } from "./server/index.ts";
11
+ export type { CreateMcpServerOptions, CreateMcpServerResult, } from "./server/server.types.ts";
12
+ export { tool } from "./tool/index.ts";
13
+ export type { ToolSpec, ToolAnnotations, ToolContext, } from "./tool/tool.types.ts";
14
+ export type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
15
+ export { mcpAuth } from "./auth/index.ts";
16
+ export type { McpAuthOptions, AuthUser } from "./auth/auth.types.ts";
17
+ export { INTERNAL_ERROR, toCallToolError } from "./errors/index.ts";
18
+ export type { McpErrorMapper, McpToolError, McpToolErrorSeverity, ToolErrorMeta, } from "./errors/errors.types.ts";
19
+ export type { RequestStore } from "./als.ts";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAE/E,OAAO,CAAC,MAAM,CAAC;IAIb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,YAAY,CAAC,EAAE,MAAM,CAAC;YACtB,IAAI,CAAC,EAAE,QAAQ,CAAC;SACjB;KACF;CACF;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EACV,QAAQ,EACR,eAAe,EACf,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,YAAY,EACV,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,aAAa,GACd,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { createMcpServer } from "./server/index.js";
2
+ export { tool } from "./tool/index.js";
3
+ export { mcpAuth } from "./auth/index.js";
4
+ export { INTERNAL_ERROR, toCallToolError } from "./errors/index.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAMpD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AASvC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG1C,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { CreateMcpServerOptions, CreateMcpServerResult } from "./server.types.ts";
2
+ /**
3
+ * Build an MCP server bound to the Streamable HTTP transport.
4
+ *
5
+ * Returns a `{ server, mount }` pair. Register tools against `server` using
6
+ * `tool()` at boot time, then call `mount(router)` to wire the JSON-RPC
7
+ * endpoint onto an Express router. Each incoming HTTP request runs through:
8
+ *
9
+ * `express.json()` → auth middleware → caller's `setupPostgan` → tool dispatch
10
+ *
11
+ * Tool handlers run inside an `AsyncLocalStorage` scope, so they pull
12
+ * `user` / `postgan` / `transaction` / `sessionId` / `logger` from
13
+ * `ToolContext` without Express objects leaking in.
14
+ *
15
+ * Synchronous and never throws.
16
+ */
17
+ export declare function createMcpServer(options: CreateMcpServerOptions): CreateMcpServerResult;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EAKtB,MAAM,mBAAmB,CAAC;AA2G3B;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAuBvB"}
@@ -0,0 +1,130 @@
1
+ import express, {} from "express";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { mcpAuth } from "../auth/index.js";
5
+ import { requestStore } from "../als.js";
6
+ /**
7
+ * Build the recording shim handed to consumers as `server`.
8
+ *
9
+ * Why a shim and not a real `McpServer`: the SDK's
10
+ * `StreamableHTTPServerTransport` (stateless mode) is single-use — once it
11
+ * has handled one request it cannot be reused. The transport must be paired
12
+ * with an `McpServer`, so we need a fresh server per HTTP request. But
13
+ * consumers register tools once at boot, not per request — so registration
14
+ * is split in two:
15
+ *
16
+ * - boot: `tool(server, spec)` lands here and pushes onto `registrations`.
17
+ * - request: {@link handleMcpRequest} constructs a real `McpServer` and
18
+ * replays every recorded registration onto it before connecting
19
+ * the transport.
20
+ *
21
+ * The recorder is typed as `McpServer` so `tool(server, spec)` type-checks,
22
+ * but `registerTool` is the only method actually implemented. Nothing in
23
+ * the library calls anything else on it, and the consumer is documented to
24
+ * only pass it to `tool()` — calls to other methods are undefined behaviour.
25
+ */
26
+ function createToolRecorder() {
27
+ const registrations = [];
28
+ const recorder = {
29
+ registerTool: (name, config, handler) => {
30
+ registrations.push({ name, config, handler });
31
+ // Real `registerTool` returns a registration handle for later
32
+ // update/remove. We don't expose that surface — empty object satisfies
33
+ // the return type and is never read.
34
+ return {};
35
+ },
36
+ };
37
+ return { server: recorder, registrations };
38
+ }
39
+ /**
40
+ * Per-request handler. Builds the ALS store from `req.user` / `req.postgan`
41
+ * (set upstream by the auth + setupPostgan middleware), spins up a fresh
42
+ * `McpServer` + transport pair, replays the recorded tool registrations,
43
+ * dispatches the JSON-RPC call inside `requestStore.run(...)`, and tears
44
+ * down server + transport in `finally`.
45
+ */
46
+ function handleMcpRequest(deps) {
47
+ return async (req, res) => {
48
+ const { user, postgan } = req;
49
+ if (!user || !postgan) {
50
+ // Defensive: mcpAuth + setupPostgan should have populated both.
51
+ res.status(401).json({ error: "Unauthenticated" });
52
+ return;
53
+ }
54
+ const sessionId = req.mcpSessionId;
55
+ const store = {
56
+ user,
57
+ postgan,
58
+ sessionId,
59
+ logger: deps.logger.child({
60
+ sessionId,
61
+ userId: user.id,
62
+ company: user.companySubdomainName,
63
+ }),
64
+ errorMapper: deps.errorMapper,
65
+ };
66
+ const requestServer = new McpServer({
67
+ name: deps.name,
68
+ version: deps.version,
69
+ });
70
+ for (const reg of deps.registrations) {
71
+ requestServer.registerTool(reg.name, reg.config, reg.handler);
72
+ }
73
+ const transport = new StreamableHTTPServerTransport({
74
+ sessionIdGenerator: undefined,
75
+ });
76
+ await requestServer.connect(transport);
77
+ await requestStore.run(store, async () => {
78
+ try {
79
+ await transport.handleRequest(req, res, req.body);
80
+ }
81
+ catch (err) {
82
+ deps.logger.error({ err, sessionId }, "mcp: transport.handleRequest threw");
83
+ if (!res.headersSent) {
84
+ res.status(500).json({ error: "Internal MCP transport error" });
85
+ }
86
+ }
87
+ finally {
88
+ await transport.close().catch((closeErr) => {
89
+ deps.logger.warn({ err: closeErr }, "mcp: transport close failed");
90
+ });
91
+ await requestServer.close().catch((closeErr) => {
92
+ deps.logger.warn({ err: closeErr }, "mcp: server close failed");
93
+ });
94
+ }
95
+ });
96
+ };
97
+ }
98
+ /**
99
+ * Build an MCP server bound to the Streamable HTTP transport.
100
+ *
101
+ * Returns a `{ server, mount }` pair. Register tools against `server` using
102
+ * `tool()` at boot time, then call `mount(router)` to wire the JSON-RPC
103
+ * endpoint onto an Express router. Each incoming HTTP request runs through:
104
+ *
105
+ * `express.json()` → auth middleware → caller's `setupPostgan` → tool dispatch
106
+ *
107
+ * Tool handlers run inside an `AsyncLocalStorage` scope, so they pull
108
+ * `user` / `postgan` / `transaction` / `sessionId` / `logger` from
109
+ * `ToolContext` without Express objects leaking in.
110
+ *
111
+ * Synchronous and never throws.
112
+ */
113
+ export function createMcpServer(options) {
114
+ const mcpLogger = options.logger.child({ component: "mcp" });
115
+ const { server, registrations } = createToolRecorder();
116
+ const mount = async (target) => {
117
+ target.use(express.json());
118
+ target.use(mcpAuth({ tokenToUser: options.tokenToUser, logger: mcpLogger }));
119
+ target.use(options.setupPostgan);
120
+ target.post("/", handleMcpRequest({
121
+ name: options.name,
122
+ version: options.version,
123
+ registrations,
124
+ logger: mcpLogger,
125
+ errorMapper: options.errorMapper,
126
+ }));
127
+ };
128
+ return { server, mount };
129
+ }
130
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import type { Request, RequestHandler, Router } from "express";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import type { Postgan } from "@ganintegrity/postgan";
4
+ import type { Logger } from "pino";
5
+ import type { AuthUser } from "../auth/auth.types.ts";
6
+ import type { McpErrorMapper } from "../errors/errors.types.ts";
7
+ /**
8
+ * Configuration for `createMcpServer()`.
9
+ */
10
+ export interface CreateMcpServerOptions {
11
+ /** MCP server name advertised to clients during initialisation. */
12
+ name: string;
13
+ /** MCP server version advertised to clients during initialisation. */
14
+ version: string;
15
+ /**
16
+ * Service logger. The library calls `logger.child({ component: "mcp" })`
17
+ * internally and further childs with `sessionId` / `userId` / `company`
18
+ * per request and with `tool` / `sessionId` per tool call.
19
+ */
20
+ logger: Logger;
21
+ /**
22
+ * Resolve a bearer token to a user. See `McpAuthOptions.tokenToUser`.
23
+ * Reject by throwing — the library responds `401`.
24
+ */
25
+ tokenToUser: (token: string) => Promise<AuthUser>;
26
+ /**
27
+ * Express middleware that attaches a `Postgan` instance to `req.postgan`.
28
+ * Mounted automatically between the auth middleware and the JSON-RPC
29
+ * dispatcher; tools open per-call transactions against `ctx.postgan`.
30
+ *
31
+ * The library is neutral about how Postgan is constructed — supply your
32
+ * service's existing setup-postgan middleware.
33
+ */
34
+ setupPostgan: RequestHandler;
35
+ /**
36
+ * Translate a thrown error into an MCP envelope. Return `null` to fall
37
+ * through to a redacted `INTERNAL_ERROR` envelope — appropriate for
38
+ * anything you don't want surfaced to the agent. Without a mapper every
39
+ * thrown error becomes `INTERNAL_ERROR`.
40
+ */
41
+ errorMapper?: McpErrorMapper;
42
+ }
43
+ /**
44
+ * Return value of `createMcpServer()`.
45
+ */
46
+ export interface CreateMcpServerResult {
47
+ /**
48
+ * Tool-registration target. Pass to `tool()` at boot, once per tool.
49
+ * Treat as opaque — `tool()` is the only supported way to use it.
50
+ */
51
+ server: McpServer;
52
+ /**
53
+ * Attach the MCP route handlers (auth + setupPostgan + JSON-RPC dispatch)
54
+ * to the supplied Express router. Caller decides the mount path
55
+ * (`app.use("/mcp", router)`).
56
+ *
57
+ * Resolves once the route is attached. Never throws.
58
+ */
59
+ mount: (target: Router) => Promise<void>;
60
+ }
61
+ export type RegisterToolArgs = Parameters<McpServer["registerTool"]>;
62
+ export type ReqWithUserPostgan = Request & {
63
+ user?: AuthUser;
64
+ postgan?: Postgan;
65
+ };
66
+ export interface ToolRegistration {
67
+ name: RegisterToolArgs[0];
68
+ config: RegisterToolArgs[1];
69
+ handler: RegisterToolArgs[2];
70
+ }
71
+ export interface HandleRequestDeps {
72
+ name: string;
73
+ version: string;
74
+ registrations: readonly ToolRegistration[];
75
+ logger: Logger;
76
+ errorMapper?: McpErrorMapper;
77
+ }
78
+ //# sourceMappingURL=server.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.types.d.ts","sourceRoot":"","sources":["../../src/server/server.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClD;;;;;;;OAOG;IACH,YAAY,EAAE,cAAc,CAAC;IAC7B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,MAAM,EAAE,SAAS,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAID,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;AAErE,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG;IACzC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC5B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.types.js","sourceRoot":"","sources":["../../src/server/server.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { z } from "zod";
3
+ import type { ToolSpec } from "./tool.types.ts";
4
+ /**
5
+ * Register a tool against the MCP server returned by `createMcpServer()`.
6
+ * The wrapper around your handler:
7
+ *
8
+ * 1. Builds a {@link ToolContext} from the active request scope.
9
+ * 2. Opens a fresh `Postgan.Transaction` before calling your handler.
10
+ * 3. On resolve, commits the transaction and returns a `CallToolResult`
11
+ * where the handler's return value is surfaced both as a JSON `text`
12
+ * content block (for non-structured-aware clients) and as
13
+ * `structuredContent` (for AI-SDK clients).
14
+ * 4. On throw, rolls back the transaction and routes the error through
15
+ * the consumer's `McpErrorMapper` (passed to `createMcpServer`) to
16
+ * build an MCP error envelope.
17
+ *
18
+ * Registration itself is synchronous and does not throw. The wrapped handler
19
+ * **may** throw at request time — but only if it is invoked outside an
20
+ * active request scope, which indicates a programming bug (the handler was
21
+ * dispatched without going through `mount()`'s ALS wrapper). Such throws
22
+ * propagate to the SDK transport and surface as an HTTP 500. Errors raised
23
+ * by your own handler logic are caught and never propagate.
24
+ */
25
+ export declare function tool<Schema extends z.ZodObject, Output extends Record<string, unknown>>(server: McpServer, spec: ToolSpec<Schema, Output>): void;
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tool/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAI7B,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AA6B7D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,IAAI,CAClB,MAAM,SAAS,CAAC,CAAC,SAAS,EAC1B,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAiDzD"}
@@ -0,0 +1,88 @@
1
+ import { requestStore } from "../als.js";
2
+ import { toCallToolError } from "../errors/index.js";
3
+ /**
4
+ * Open a postgan transaction, run `body` against it, and finalise:
5
+ * commit on resolve, rollback on throw. A failing rollback is logged at
6
+ * error level but never re-thrown — the original error from `body` is what
7
+ * propagates.
8
+ */
9
+ async function withTransaction(postgan, logger, body) {
10
+ const tx = new postgan.Transaction();
11
+ await tx.begin();
12
+ try {
13
+ const result = await body(tx);
14
+ await tx.commit();
15
+ return result;
16
+ }
17
+ catch (err) {
18
+ if (tx.active) {
19
+ await tx.rollback().catch((rollbackErr) => {
20
+ logger.error({ err: rollbackErr }, "mcp: transaction rollback failed");
21
+ });
22
+ }
23
+ throw err;
24
+ }
25
+ }
26
+ /**
27
+ * Register a tool against the MCP server returned by `createMcpServer()`.
28
+ * The wrapper around your handler:
29
+ *
30
+ * 1. Builds a {@link ToolContext} from the active request scope.
31
+ * 2. Opens a fresh `Postgan.Transaction` before calling your handler.
32
+ * 3. On resolve, commits the transaction and returns a `CallToolResult`
33
+ * where the handler's return value is surfaced both as a JSON `text`
34
+ * content block (for non-structured-aware clients) and as
35
+ * `structuredContent` (for AI-SDK clients).
36
+ * 4. On throw, rolls back the transaction and routes the error through
37
+ * the consumer's `McpErrorMapper` (passed to `createMcpServer`) to
38
+ * build an MCP error envelope.
39
+ *
40
+ * Registration itself is synchronous and does not throw. The wrapped handler
41
+ * **may** throw at request time — but only if it is invoked outside an
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.
46
+ */
47
+ export function tool(server, spec) {
48
+ server.registerTool(spec.name, {
49
+ description: spec.description,
50
+ inputSchema: spec.inputSchema.shape,
51
+ ...(spec.annotations ? { annotations: spec.annotations } : {}),
52
+ }, async (args, extra) => {
53
+ const store = requestStore.getStore();
54
+ if (!store) {
55
+ // Unreachable: createMcpServer.mount() always wraps tool dispatch in
56
+ // requestStore.run(). Throw to surface the bug rather than silently
57
+ // returning an error envelope without a logger.
58
+ throw new Error("mcp tool invoked outside request scope");
59
+ }
60
+ const sessionId = store.sessionId ?? extra?.sessionId;
61
+ const logger = store.logger.child({ tool: spec.name, sessionId });
62
+ try {
63
+ const result = await withTransaction(store.postgan, logger, (transaction) => {
64
+ const ctx = {
65
+ user: store.user,
66
+ postgan: store.postgan,
67
+ transaction,
68
+ sessionId,
69
+ logger,
70
+ };
71
+ return spec.handler(args, ctx);
72
+ });
73
+ return {
74
+ content: [{ type: "text", text: JSON.stringify(result) }],
75
+ structuredContent: result,
76
+ };
77
+ }
78
+ catch (err) {
79
+ const mapped = store.errorMapper?.(err) ?? null;
80
+ return toCallToolError(mapped, err, {
81
+ tool: spec.name,
82
+ sessionId,
83
+ logger,
84
+ });
85
+ }
86
+ });
87
+ }
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tool/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import type { Postgan, PostganTransaction } from "@ganintegrity/postgan";
2
+ import type { Logger } from "pino";
3
+ import type { z } from "zod";
4
+ import type { AuthUser } from "../auth/auth.types.ts";
5
+ /**
6
+ * What every tool handler receives as its second argument.
7
+ */
8
+ export interface ToolContext {
9
+ /** Authenticated user. Cast to your service's richer type for extra fields. */
10
+ user: AuthUser;
11
+ /** Per-request Postgan instance. */
12
+ postgan: Postgan;
13
+ /**
14
+ * Transaction opened immediately before the handler runs. Auto-committed
15
+ * if the handler resolves; rolled back if it throws. **Do not call
16
+ * `commit()` or `rollback()` yourself** — the library owns the lifecycle.
17
+ */
18
+ transaction: PostganTransaction;
19
+ /** Forwarded `X-Session-Id` header value if present. Useful for log correlation. */
20
+ sessionId?: string;
21
+ /** Logger childed with this tool's name and the session id. */
22
+ logger: Logger;
23
+ }
24
+ /**
25
+ * MCP-spec tool annotations surfaced to clients during `tools/list`. All
26
+ * fields are optional hints — clients use them to decide things like whether
27
+ * to auto-approve calls or warn users.
28
+ *
29
+ * Pick honestly: `readOnlyHint: true` on a tool that mutates is worse than
30
+ * leaving the hint unset.
31
+ */
32
+ export interface ToolAnnotations {
33
+ /** Human-readable display title (defaults to `name` if omitted). */
34
+ title?: string;
35
+ /** True if the tool only reads — never writes or mutates state. */
36
+ readOnlyHint?: boolean;
37
+ /** True if the tool may delete or destroy data. */
38
+ destructiveHint?: boolean;
39
+ /** True if calling twice with the same args produces the same result. */
40
+ idempotentHint?: boolean;
41
+ /** True if the tool reaches out to external systems (network, third-party APIs). */
42
+ openWorldHint?: boolean;
43
+ }
44
+ /**
45
+ * Specification passed to `tool()`. Defines the tool's name, description,
46
+ * input schema, optional annotations, and the handler that executes it.
47
+ *
48
+ * @template Schema Zod object schema describing the tool's input.
49
+ * @template Output Plain object the handler returns. Surfaced as both a JSON
50
+ * `text` content block and as `structuredContent`.
51
+ */
52
+ export interface ToolSpec<Schema extends z.ZodObject, Output> {
53
+ /** Stable identifier the agent uses to invoke the tool. */
54
+ name: string;
55
+ /**
56
+ * Description shown to the agent. Treat this as a prompt — be precise about
57
+ * when to call the tool, when not to, and how to interpret the output.
58
+ */
59
+ description: string;
60
+ /** Zod object schema. The library forwards `.shape` to the SDK. */
61
+ inputSchema: Schema;
62
+ /** Optional MCP annotations; see {@link ToolAnnotations}. */
63
+ annotations?: ToolAnnotations;
64
+ /**
65
+ * The actual tool implementation. Receives the parsed input plus the
66
+ * per-call {@link ToolContext}. Throw to signal failure — the wrapper
67
+ * rolls back the transaction and routes the error through the consumer's
68
+ * `McpErrorMapper` to build an MCP error envelope.
69
+ */
70
+ handler: (args: z.infer<Schema>, ctx: ToolContext) => Promise<Output>;
71
+ }
72
+ //# sourceMappingURL=tool.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.types.d.ts","sourceRoot":"","sources":["../../src/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;;GAEG;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;;;;;;;GAOG;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;;;;;;;GAOG;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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tool.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.types.js","sourceRoot":"","sources":["../../src/tool/tool.types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@ganintegrity/mcp",
3
+ "version": "1.0.0",
4
+ "description": "Provides tooling to scaffold an MCP server",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "test": "vitest run",
21
+ "test:watch": "vitest",
22
+ "test:coverage": "vitest run --coverage",
23
+ "lint": "eslint 'src/**/*.ts'",
24
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
25
+ "format": "pnpx prettier . -w",
26
+ "format:check": "pnpx prettier . -c",
27
+ "typecheck:watch": "tsc --noEmit --watch"
28
+ },
29
+ "keywords": [
30
+ "mcp",
31
+ "ai"
32
+ ],
33
+ "author": "GAN Integrity",
34
+ "license": "Proprietary",
35
+ "packageManager": "pnpm@10.33.0",
36
+ "peerDependencies": {
37
+ "@ganintegrity/postgan": "^28",
38
+ "@ganintegrity/postgres-migrations": "^16",
39
+ "express": "^5",
40
+ "pino": "^10",
41
+ "zod": "^4"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "1.29.0"
45
+ },
46
+ "devDependencies": {
47
+ "@commitlint/cli": "^20.5.3",
48
+ "@commitlint/config-conventional": "^20.5.3",
49
+ "@eslint/js": "^10.0.1",
50
+ "@semantic-release/changelog": "^6.0.3",
51
+ "@semantic-release/gitlab": "^13.3.2",
52
+ "@types/express": "^5.0.6",
53
+ "@types/node": "^25.6.0",
54
+ "@types/supertest": "^7.2.0",
55
+ "@vitest/coverage-v8": "^4.1.4",
56
+ "eslint": "^10.3.0",
57
+ "fallow": "^2.58.0",
58
+ "prettier": "^3.8.3",
59
+ "semantic-release": "^25.0.3",
60
+ "supertest": "^7.2.2",
61
+ "typescript": "^6.0.3",
62
+ "typescript-eslint": "^8.59.1",
63
+ "vitest": "^4.1.4"
64
+ }
65
+ }