@jaypie/mcp 0.8.152 → 0.8.154
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 +34 -0
- package/dist/createMcpServer.d.ts +5 -0
- package/dist/createMcpServer.js +3 -2
- package/dist/createMcpServer.js.map +1 -1
- package/dist/http/index.d.ts +92 -0
- package/dist/http/index.js +3 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/mcpHttpHandler.d.ts +35 -0
- package/dist/http/mcpHttpHandler.js +99 -0
- package/dist/http/mcpHttpHandler.js.map +1 -0
- package/dist/http/rpc.d.ts +70 -0
- package/dist/http/rpc.js +262 -0
- package/dist/http/rpc.js.map +1 -0
- package/dist/http/tools.d.ts +16 -0
- package/dist/http/tools.js +23 -0
- package/dist/http/tools.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/mcpExpressHandler.d.ts +5 -0
- package/dist/mcpExpressHandler.js +2 -2
- package/dist/mcpExpressHandler.js.map +1 -1
- package/dist/suites/docs/index.js +1 -1
- package/package.json +27 -3
- package/release-notes/constructs/1.2.82.md +16 -0
- package/release-notes/constructs/1.2.83.md +21 -0
- package/release-notes/datadog/1.2.8.md +19 -0
- package/release-notes/dynamodb/0.6.11.md +13 -0
- package/release-notes/express/1.2.37.md +34 -0
- package/release-notes/fabric/0.3.12.md +20 -0
- package/release-notes/jaypie/1.2.101.md +12 -0
- package/release-notes/mcp/0.8.153.md +37 -0
- package/release-notes/mcp/0.8.154.md +11 -0
- package/release-notes/testkit/1.2.73.md +15 -0
- package/skills/apigateway.md +1 -1
- package/skills/aws.md +2 -1
- package/skills/cdk.md +5 -5
- package/skills/datadog.md +15 -2
- package/skills/dynamodb.md +3 -7
- package/skills/express.md +56 -2
- package/skills/fabric.md +14 -1
- package/skills/lambda.md +3 -3
- package/skills/mcp.md +79 -1
- package/skills/streaming.md +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.js","sources":["../../src/http/rpc.ts"],"sourcesContent":["import { isJaypieError } from \"@jaypie/errors\";\nimport type { ServiceSuite } from \"@jaypie/fabric\";\nimport { inputToJsonSchema } from \"@jaypie/fabric/llm\";\nimport { log } from \"@jaypie/logger\";\n\nimport { findTool, selectTools } from \"./tools.js\";\n\n//\n//\n// Constants\n//\n\nexport const JSON_RPC_ERROR = {\n INTERNAL: -32603,\n INVALID_PARAMS: -32602,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n PARSE: -32700,\n} as const;\n\nexport const JSON_RPC_VERSION = \"2.0\";\n\nexport const MCP_METHOD = {\n CALL_TOOL: \"tools/call\",\n CANCELLED: \"notifications/cancelled\",\n INITIALIZE: \"initialize\",\n INITIALIZED: \"notifications/initialized\",\n LIST_TOOLS: \"tools/list\",\n PING: \"ping\",\n} as const;\n\n/** Latest protocol version; answered when a client requests an unknown one */\nexport const MCP_PROTOCOL_VERSION = \"2025-06-18\";\n\nexport const MCP_SUPPORTED_PROTOCOL_VERSIONS: readonly string[] = [\n MCP_PROTOCOL_VERSION,\n \"2025-03-26\",\n \"2024-11-05\",\n];\n\nconst MESSAGE = {\n EMPTY_BATCH: \"An empty batch is not a request\",\n INVALID_ARGUMENTS: \"Tool arguments must be an object\",\n INVALID_REQUEST: \"The request is not a JSON-RPC request\",\n PARSE: \"The body is not JSON-RPC\",\n TOOL_FAILED: \"The tool call failed\",\n UNKNOWN_METHOD: \"Unknown method\",\n UNKNOWN_TOOL: \"Unknown tool\",\n} as const;\n\n//\n//\n// Types\n//\n\nexport type JsonRpcId = number | string | null;\n\nexport interface JsonRpcRequest {\n id?: JsonRpcId;\n jsonrpc?: string;\n method?: string;\n params?: Record<string, unknown>;\n}\n\nexport interface JsonRpcResponse {\n error?: { code: number; data?: unknown; message: string };\n id: JsonRpcId;\n jsonrpc: typeof JSON_RPC_VERSION;\n result?: unknown;\n}\n\nexport interface McpRpcOptions {\n /** Server name reported by `initialize`. Defaults to the suite name */\n name?: string;\n /** Allowlist of service aliases exposed as tools. Omit to expose all */\n services?: string[];\n /** Suite served as tools. Defaults to the Jaypie MCP suite */\n suite?: ServiceSuite;\n /** Server version reported by `initialize`. Defaults to the suite version */\n version?: string;\n}\n\n//\n//\n// Helpers\n//\n\nlet defaultSuite: Promise<ServiceSuite> | undefined;\n\n/** Load the Jaypie suite only when no suite is supplied */\nfunction loadDefaultSuite(): Promise<ServiceSuite> {\n if (!defaultSuite) {\n defaultSuite = import(\"../suite.js\")\n .then((module) => module.suite)\n .catch((error: unknown) => {\n defaultSuite = undefined;\n throw error;\n });\n }\n return defaultSuite;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction jsonRpcError({\n code,\n id = null,\n message,\n}: {\n code: number;\n id?: JsonRpcId;\n message: string;\n}): JsonRpcResponse {\n return { error: { code, message }, id, jsonrpc: JSON_RPC_VERSION };\n}\n\nfunction jsonRpcResult({\n id,\n result,\n}: {\n id: JsonRpcId;\n result: unknown;\n}): JsonRpcResponse {\n return { id, jsonrpc: JSON_RPC_VERSION, result };\n}\n\nfunction textContent(value: unknown): { text: string; type: \"text\" }[] {\n let text: string;\n if (value === undefined || value === null) {\n text = \"\";\n } else if (typeof value === \"string\") {\n text = value;\n } else {\n text = JSON.stringify(value, null, 2);\n }\n return [{ text, type: \"text\" }];\n}\n\n/** A notification carries no id and expects no response */\nexport function isNotification(request: unknown): boolean {\n return isRecord(request) && (request.id === undefined || request.id === null);\n}\n\n/**\n * Normalize a raw body: a Buffer or string is parsed as JSON; anything else is\n * taken as already parsed. Returns `undefined` when there is no parseable body.\n */\nexport function parseRpcBody(body: unknown): unknown {\n const raw = Buffer.isBuffer(body) ? body.toString(\"utf8\") : body;\n if (typeof raw !== \"string\") {\n return raw;\n }\n try {\n return JSON.parse(raw);\n } catch {\n return undefined;\n }\n}\n\n/** Does the body carry anything that must be answered? */\nexport function expectsResponse(body: unknown): boolean {\n const parsed = parseRpcBody(body);\n if (Array.isArray(parsed)) {\n return (\n parsed.length === 0 || parsed.some((entry) => !isNotification(entry))\n );\n }\n return !isNotification(parsed);\n}\n\nasync function callTool({\n id,\n params,\n services,\n suite,\n}: {\n id: JsonRpcId;\n params: Record<string, unknown>;\n services?: string[];\n suite: ServiceSuite;\n}): Promise<JsonRpcResponse> {\n const name = typeof params.name === \"string\" ? params.name : \"\";\n const tool = findTool(name, { services, suite });\n if (!tool) {\n return jsonRpcError({\n code: JSON_RPC_ERROR.INVALID_PARAMS,\n id,\n message: `${MESSAGE.UNKNOWN_TOOL}: ${name}`,\n });\n }\n\n const args = params.arguments ?? {};\n if (!isRecord(args)) {\n return jsonRpcError({\n code: JSON_RPC_ERROR.INVALID_PARAMS,\n id,\n message: MESSAGE.INVALID_ARGUMENTS,\n });\n }\n\n try {\n const result = await tool(args);\n log.trace(`[mcp] Tool call complete: ${name}`);\n return jsonRpcResult({ id, result: { content: textContent(result) } });\n } catch (error) {\n let message: string = MESSAGE.TOOL_FAILED;\n if (isJaypieError(error) && error instanceof Error) {\n message = error.message;\n log.debug(`[mcp] Tool call rejected: ${name}`);\n } else {\n log.warn(`[mcp] Tool call failed: ${name}`);\n }\n log.var({\n mcpToolError: {\n message: error instanceof Error ? error.message : String(error),\n tool: name,\n },\n });\n return jsonRpcResult({\n id,\n result: { content: textContent(message), isError: true },\n });\n }\n}\n\n//\n//\n// Main\n//\n\n/**\n * Answer one JSON-RPC request against a suite\n *\n * Returns `null` for a notification, which the transport answers with 202 and\n * no body.\n */\nexport async function handleMcpRpc(\n request: JsonRpcRequest,\n options: McpRpcOptions = {},\n): Promise<JsonRpcResponse | null> {\n const id = request.id ?? null;\n const notification = isNotification(request);\n\n if (typeof request.method !== \"string\") {\n if (notification) {\n return null;\n }\n return jsonRpcError({\n code: JSON_RPC_ERROR.INVALID_REQUEST,\n id,\n message: MESSAGE.INVALID_REQUEST,\n });\n }\n\n const suite = options.suite ?? (await loadDefaultSuite());\n const { name = suite.name, services, version = suite.version } = options;\n const params = isRecord(request.params) ? request.params : {};\n\n log.trace(`[mcp] ${request.method}`);\n\n switch (request.method) {\n case MCP_METHOD.INITIALIZE: {\n const requested = params.protocolVersion;\n const protocolVersion =\n typeof requested === \"string\" &&\n MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(requested)\n ? requested\n : MCP_PROTOCOL_VERSION;\n return jsonRpcResult({\n id,\n result: {\n capabilities: { tools: {} },\n protocolVersion,\n serverInfo: { name, version },\n },\n });\n }\n\n case MCP_METHOD.CANCELLED:\n case MCP_METHOD.INITIALIZED:\n return null;\n\n case MCP_METHOD.PING:\n return jsonRpcResult({ id, result: {} });\n\n case MCP_METHOD.LIST_TOOLS:\n return jsonRpcResult({\n id,\n result: {\n tools: selectTools({ services, suite }).map((tool) => ({\n description: tool.description ?? \"\",\n inputSchema: inputToJsonSchema(tool.input),\n name: String(tool.alias),\n })),\n },\n });\n\n case MCP_METHOD.CALL_TOOL:\n return callTool({ id, params, services, suite });\n\n default:\n if (notification) {\n return null;\n }\n return jsonRpcError({\n code: JSON_RPC_ERROR.METHOD_NOT_FOUND,\n id,\n message: `${MESSAGE.UNKNOWN_METHOD}: ${request.method}`,\n });\n }\n}\n\n/**\n * Answer a body that may be one request or a batch\n *\n * Accepts a parsed body, a JSON string, or a Buffer. Returns `null` when\n * nothing needs an answer.\n */\nexport async function handleMcpRpcBody(\n body: unknown,\n options: McpRpcOptions = {},\n): Promise<JsonRpcResponse | JsonRpcResponse[] | null> {\n const parsed = parseRpcBody(body);\n\n if (parsed === undefined) {\n return jsonRpcError({ code: JSON_RPC_ERROR.PARSE, message: MESSAGE.PARSE });\n }\n\n if (Array.isArray(parsed)) {\n if (parsed.length === 0) {\n return jsonRpcError({\n code: JSON_RPC_ERROR.INVALID_REQUEST,\n message: MESSAGE.EMPTY_BATCH,\n });\n }\n const responses = await Promise.all(\n parsed.map((entry) =>\n isRecord(entry)\n ? handleMcpRpc(entry as JsonRpcRequest, options)\n : jsonRpcError({\n code: JSON_RPC_ERROR.INVALID_REQUEST,\n message: MESSAGE.INVALID_REQUEST,\n }),\n ),\n );\n const answered = responses.filter(\n (response): response is JsonRpcResponse => response !== null,\n );\n return answered.length > 0 ? answered : null;\n }\n\n if (!isRecord(parsed)) {\n return jsonRpcError({\n code: JSON_RPC_ERROR.INVALID_REQUEST,\n message: MESSAGE.INVALID_REQUEST,\n });\n }\n\n return handleMcpRpc(parsed as JsonRpcRequest, options);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Service, ServiceSuite } from "@jaypie/fabric";
|
|
2
|
+
export interface SelectToolsOptions {
|
|
3
|
+
/** Allowlist of service aliases. Omit to select every service */
|
|
4
|
+
services?: string[];
|
|
5
|
+
suite: ServiceSuite;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Select the services a suite exposes as MCP tools
|
|
9
|
+
*
|
|
10
|
+
* Delegates to `selectServiceFunctions` from `@jaypie/fabric`, the same
|
|
11
|
+
* selection `createMcpServerFromSuite` applies, so every transport narrows
|
|
12
|
+
* tools identically.
|
|
13
|
+
*/
|
|
14
|
+
export declare function selectTools({ services, suite, }: SelectToolsOptions): Service[];
|
|
15
|
+
/** Find one exposed tool by name; tools outside the allowlist are absent */
|
|
16
|
+
export declare function findTool(name: string, options: SelectToolsOptions): Service | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { selectServiceFunctions } from '@jaypie/fabric';
|
|
2
|
+
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Main
|
|
6
|
+
//
|
|
7
|
+
/**
|
|
8
|
+
* Select the services a suite exposes as MCP tools
|
|
9
|
+
*
|
|
10
|
+
* Delegates to `selectServiceFunctions` from `@jaypie/fabric`, the same
|
|
11
|
+
* selection `createMcpServerFromSuite` applies, so every transport narrows
|
|
12
|
+
* tools identically.
|
|
13
|
+
*/
|
|
14
|
+
function selectTools({ services, suite, }) {
|
|
15
|
+
return selectServiceFunctions(suite, { services });
|
|
16
|
+
}
|
|
17
|
+
/** Find one exposed tool by name; tools outside the allowlist are absent */
|
|
18
|
+
function findTool(name, options) {
|
|
19
|
+
return selectTools(options).find((tool) => tool.alias === name);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { findTool, selectTools };
|
|
23
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sources":["../../src/http/tools.ts"],"sourcesContent":["import { selectServiceFunctions } from \"@jaypie/fabric\";\nimport type { Service, ServiceSuite } from \"@jaypie/fabric\";\n\n//\n//\n// Types\n//\n\nexport interface SelectToolsOptions {\n /** Allowlist of service aliases. Omit to select every service */\n services?: string[];\n suite: ServiceSuite;\n}\n\n//\n//\n// Main\n//\n\n/**\n * Select the services a suite exposes as MCP tools\n *\n * Delegates to `selectServiceFunctions` from `@jaypie/fabric`, the same\n * selection `createMcpServerFromSuite` applies, so every transport narrows\n * tools identically.\n */\nexport function selectTools({\n services,\n suite,\n}: SelectToolsOptions): Service[] {\n return selectServiceFunctions(suite, { services });\n}\n\n/** Find one exposed tool by name; tools outside the allowlist are absent */\nexport function findTool(\n name: string,\n options: SelectToolsOptions,\n): Service | undefined {\n return selectTools(options).find((tool) => tool.alias === name);\n}\n"],"names":[],"mappings":";;AAcA;AACA;AACA;AACA;AAEA;;;;;;AAMG;SACa,WAAW,CAAC,EAC1B,QAAQ,EACR,KAAK,GACc,EAAA;IACnB,OAAO,sBAAsB,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC;AACpD;AAEA;AACM,SAAU,QAAQ,CACtB,IAAY,EACZ,OAA2B,EAAA;AAE3B,IAAA,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;AACjE;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
3
3
|
import { Request, Response } from 'express';
|
|
4
4
|
|
|
5
5
|
interface CreateMcpServerOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Allowlist of tool names (service aliases) to expose. Omit to expose every
|
|
8
|
+
* tool; an empty array exposes none.
|
|
9
|
+
*/
|
|
10
|
+
services?: string[];
|
|
6
11
|
version?: string;
|
|
7
12
|
verbose?: boolean;
|
|
8
13
|
}
|
|
@@ -32,6 +37,11 @@ interface McpExpressHandlerOptions {
|
|
|
32
37
|
* Default: true
|
|
33
38
|
*/
|
|
34
39
|
enableSessions?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Allowlist of tool names (service aliases) to expose. Omit to expose every
|
|
42
|
+
* tool
|
|
43
|
+
*/
|
|
44
|
+
services?: string[];
|
|
35
45
|
/**
|
|
36
46
|
* Custom session ID generator function
|
|
37
47
|
*/
|
|
@@ -12,6 +12,11 @@ export interface McpExpressHandlerOptions {
|
|
|
12
12
|
* Default: true
|
|
13
13
|
*/
|
|
14
14
|
enableSessions?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Allowlist of tool names (service aliases) to expose. Omit to expose every
|
|
17
|
+
* tool
|
|
18
|
+
*/
|
|
19
|
+
services?: string[];
|
|
15
20
|
/**
|
|
16
21
|
* Custom session ID generator function
|
|
17
22
|
*/
|
|
@@ -30,8 +30,8 @@ const DEFAULT_VERSION = "0.0.0";
|
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
32
|
async function mcpExpressHandler(options = {}) {
|
|
33
|
-
const { version = DEFAULT_VERSION, enableSessions = true, sessionIdGenerator = () => randomUUID(), enableJsonResponse = false, } = options;
|
|
34
|
-
const server = createMcpServer(version);
|
|
33
|
+
const { version = DEFAULT_VERSION, enableSessions = true, sessionIdGenerator = () => randomUUID(), enableJsonResponse = false, services, } = options;
|
|
34
|
+
const server = createMcpServer({ services, version });
|
|
35
35
|
const transport = new StreamableHTTPServerTransport({
|
|
36
36
|
sessionIdGenerator: enableSessions ? sessionIdGenerator : undefined,
|
|
37
37
|
enableJsonResponse,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcpExpressHandler.js","sources":["../src/mcpExpressHandler.ts"],"sourcesContent":["import { Request, Response } from \"express\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { randomUUID } from \"node:crypto\";\nimport { createMcpServer } from \"./createMcpServer.js\";\n\n// Version will be injected during build\nconst DEFAULT_VERSION = \"0.0.0\";\n\n/**\n * Options for configuring the MCP Express handler\n */\nexport interface McpExpressHandlerOptions {\n /**\n * Version string for the MCP server\n */\n version?: string;\n /**\n * Whether to enable session management (stateful mode)\n * Default: true\n */\n enableSessions?: boolean;\n /**\n * Custom session ID generator function\n */\n sessionIdGenerator?: () => string;\n /**\n * Enable JSON responses instead of SSE streaming\n * Default: false\n */\n enableJsonResponse?: boolean;\n}\n\n/**\n * Creates an Express handler for the Jaypie MCP server using HTTP transport\n *\n * @param options - Configuration options for the handler\n * @returns Promise that resolves to an Express middleware function\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { mcpExpressHandler } from '@jaypie/mcp';\n *\n * const app = express();\n * app.use(express.json());\n *\n * // Note: mcpExpressHandler is now async\n * app.use('/mcp', await mcpExpressHandler({\n * version: '1.0.0',\n * enableSessions: true\n * }));\n *\n * app.listen(3000, () => {\n * console.log('MCP server running on http://localhost:3000/mcp');\n * });\n * ```\n */\nexport async function mcpExpressHandler(\n options: McpExpressHandlerOptions = {},\n): Promise<(req: Request, res: Response) => Promise<void>> {\n const {\n version = DEFAULT_VERSION,\n enableSessions = true,\n sessionIdGenerator = () => randomUUID(),\n enableJsonResponse = false,\n } = options;\n\n const server = createMcpServer(version);\n\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: enableSessions ? sessionIdGenerator : undefined,\n enableJsonResponse,\n });\n\n await server.connect(transport);\n\n return async (req: Request, res: Response): Promise<void> => {\n try {\n await transport.handleRequest(req, res, req.body);\n } catch (error) {\n if (!res.headersSent) {\n res.status(500).json({\n error: \"Internal server error\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n };\n}\n"],"names":[],"mappings":";;;;AAKA;AACA,MAAM,eAAe,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"mcpExpressHandler.js","sources":["../src/mcpExpressHandler.ts"],"sourcesContent":["import { Request, Response } from \"express\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { randomUUID } from \"node:crypto\";\nimport { createMcpServer } from \"./createMcpServer.js\";\n\n// Version will be injected during build\nconst DEFAULT_VERSION = \"0.0.0\";\n\n/**\n * Options for configuring the MCP Express handler\n */\nexport interface McpExpressHandlerOptions {\n /**\n * Version string for the MCP server\n */\n version?: string;\n /**\n * Whether to enable session management (stateful mode)\n * Default: true\n */\n enableSessions?: boolean;\n /**\n * Allowlist of tool names (service aliases) to expose. Omit to expose every\n * tool\n */\n services?: string[];\n /**\n * Custom session ID generator function\n */\n sessionIdGenerator?: () => string;\n /**\n * Enable JSON responses instead of SSE streaming\n * Default: false\n */\n enableJsonResponse?: boolean;\n}\n\n/**\n * Creates an Express handler for the Jaypie MCP server using HTTP transport\n *\n * @param options - Configuration options for the handler\n * @returns Promise that resolves to an Express middleware function\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { mcpExpressHandler } from '@jaypie/mcp';\n *\n * const app = express();\n * app.use(express.json());\n *\n * // Note: mcpExpressHandler is now async\n * app.use('/mcp', await mcpExpressHandler({\n * version: '1.0.0',\n * enableSessions: true\n * }));\n *\n * app.listen(3000, () => {\n * console.log('MCP server running on http://localhost:3000/mcp');\n * });\n * ```\n */\nexport async function mcpExpressHandler(\n options: McpExpressHandlerOptions = {},\n): Promise<(req: Request, res: Response) => Promise<void>> {\n const {\n version = DEFAULT_VERSION,\n enableSessions = true,\n sessionIdGenerator = () => randomUUID(),\n enableJsonResponse = false,\n services,\n } = options;\n\n const server = createMcpServer({ services, version });\n\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: enableSessions ? sessionIdGenerator : undefined,\n enableJsonResponse,\n });\n\n await server.connect(transport);\n\n return async (req: Request, res: Response): Promise<void> => {\n try {\n await transport.handleRequest(req, res, req.body);\n } catch (error) {\n if (!res.headersSent) {\n res.status(500).json({\n error: \"Internal server error\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n };\n}\n"],"names":[],"mappings":";;;;AAKA;AACA,MAAM,eAAe,GAAG,OAAO;AA+B/B;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACI,eAAe,iBAAiB,CACrC,UAAoC,EAAE,EAAA;IAEtC,MAAM,EACJ,OAAO,GAAG,eAAe,EACzB,cAAc,GAAG,IAAI,EACrB,kBAAkB,GAAG,MAAM,UAAU,EAAE,EACvC,kBAAkB,GAAG,KAAK,EAC1B,QAAQ,GACT,GAAG,OAAO;IAEX,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAErD,IAAA,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;QAClD,kBAAkB,EAAE,cAAc,GAAG,kBAAkB,GAAG,SAAS;QACnE,kBAAkB;AACnB,KAAA,CAAC;AAEF,IAAA,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;AAE/B,IAAA,OAAO,OAAO,GAAY,EAAE,GAAa,KAAmB;AAC1D,QAAA,IAAI;AACF,YAAA,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC;QACnD;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;AACpB,gBAAA,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;AACnB,oBAAA,KAAK,EAAE,uBAAuB;AAC9B,oBAAA,OAAO,EAAE,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,eAAe;AAClE,iBAAA,CAAC;YACJ;QACF;AACF,IAAA,CAAC;AACH;;;;"}
|
|
@@ -10,7 +10,7 @@ import { gt } from 'semver';
|
|
|
10
10
|
/**
|
|
11
11
|
* Docs Suite - Documentation services (skill, version, release_notes)
|
|
12
12
|
*/
|
|
13
|
-
const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.
|
|
13
|
+
const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.154#f76841e4"
|
|
14
14
|
;
|
|
15
15
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
16
16
|
const __dirname$1 = path.dirname(__filename$1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaypie/mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.154",
|
|
4
4
|
"description": "Jaypie MCP",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
"default": "./dist/index.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
|
+
"./http": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/http/index.d.ts",
|
|
22
|
+
"default": "./dist/http/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
19
25
|
"./suite": {
|
|
20
26
|
"import": {
|
|
21
27
|
"types": "./dist/suite.d.ts",
|
|
@@ -43,9 +49,9 @@
|
|
|
43
49
|
"typecheck": "tsc --noEmit"
|
|
44
50
|
},
|
|
45
51
|
"dependencies": {
|
|
46
|
-
"@jaypie/datadog": "^1.2.
|
|
52
|
+
"@jaypie/datadog": "^1.2.8",
|
|
47
53
|
"@jaypie/errors": "^1.2.6",
|
|
48
|
-
"@jaypie/fabric": "^0.3.
|
|
54
|
+
"@jaypie/fabric": "^0.3.12",
|
|
49
55
|
"@jaypie/kit": "^1.2.12",
|
|
50
56
|
"@jaypie/tildeskill": "^0.3.3",
|
|
51
57
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -54,6 +60,8 @@
|
|
|
54
60
|
"zod": "^4.1.13"
|
|
55
61
|
},
|
|
56
62
|
"devDependencies": {
|
|
63
|
+
"@jaypie/express": "^1.2.37",
|
|
64
|
+
"@jaypie/logger": "^1.2.24",
|
|
57
65
|
"@rollup/plugin-replace": "^6.0.3",
|
|
58
66
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
59
67
|
"@types/express": "^5.0.3",
|
|
@@ -64,6 +72,22 @@
|
|
|
64
72
|
"rollup-plugin-dts": "^6.1.1",
|
|
65
73
|
"typescript": "^5.9.3"
|
|
66
74
|
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"@jaypie/express": "^1.2.37",
|
|
77
|
+
"@jaypie/logger": "^1.2.24",
|
|
78
|
+
"express": ">=4.0.0"
|
|
79
|
+
},
|
|
80
|
+
"peerDependenciesMeta": {
|
|
81
|
+
"@jaypie/express": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@jaypie/logger": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"express": {
|
|
88
|
+
"optional": true
|
|
89
|
+
}
|
|
90
|
+
},
|
|
67
91
|
"publishConfig": {
|
|
68
92
|
"access": "public"
|
|
69
93
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.82
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: JaypieDistributionProps JSDoc states the actual roleTag, host, and zone defaults
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`roleTag`** (#536) documents `@default CDK.ROLE.API`, matching the
|
|
10
|
+
constructor. It previously claimed `CDK.ROLE.HOSTING`.
|
|
11
|
+
- **`host`** documents that `CDK_ENV_API_HOST_NAME` is checked first, then
|
|
12
|
+
`CDK_ENV_API_SUBDOMAIN` merged with `CDK_ENV_API_HOSTED_ZONE || CDK_ENV_HOSTED_ZONE`.
|
|
13
|
+
- **`zone`** documents `@default CDK_ENV_HOSTED_ZONE`. The code does not read
|
|
14
|
+
`CDK_ENV_API_HOSTED_ZONE` for the zone.
|
|
15
|
+
|
|
16
|
+
No runtime behavior changed.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.83
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: JaypieDistribution resolves zone from CDK_ENV_API_HOSTED_ZONE before CDK_ENV_HOSTED_ZONE
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`JaypieDistribution` `zone`** falls back to
|
|
10
|
+
`CDK_ENV_API_HOSTED_ZONE || CDK_ENV_HOSTED_ZONE`, matching `host` and
|
|
11
|
+
`JaypieCertificate`. Previously `zone` read only `CDK_ENV_HOSTED_ZONE`, so a
|
|
12
|
+
stack setting only `CDK_ENV_API_HOSTED_ZONE` resolved a host but created no
|
|
13
|
+
certificate or DNS records.
|
|
14
|
+
|
|
15
|
+
## Upgrade
|
|
16
|
+
|
|
17
|
+
A stack that sets both variables to different zones now places the certificate
|
|
18
|
+
and DNS records in the `CDK_ENV_API_HOSTED_ZONE` zone. Pass `zone` explicitly to
|
|
19
|
+
keep the previous zone.
|
|
20
|
+
|
|
21
|
+
Jaypie 2 consolidates on `CDK_ENV_HOSTED_ZONE` alone.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.8
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: hasDatadogEnv recognizes secret references; metric submission rejects with BadGatewayError
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`hasDatadogEnv` recognizes every key source** (#513). `DD_API_KEY` and the
|
|
10
|
+
`SECRET_<NAME>` / `<NAME>_SECRET` references that `getEnvSecret` resolves now
|
|
11
|
+
count as present. A key held only in Secrets Manager (for example
|
|
12
|
+
`DATADOG_API_KEY_SECRET`) turns on `expressHandler` response metrics.
|
|
13
|
+
Detection reads variable names only and fetches nothing.
|
|
14
|
+
- **Jaypie errors from metric submission** (#516). A failed Datadog response or
|
|
15
|
+
connection error rejects with `BadGatewayError` rather than a vanilla `Error`.
|
|
16
|
+
`submitMetric`, `submitMetricSet`, and `submitDistribution` still catch and
|
|
17
|
+
return `false`.
|
|
18
|
+
- Tests cover a Datadog 403 through `datadogService` returning
|
|
19
|
+
`success: false` with a readable error.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.6.11
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: updateEntity removes a row from a sparse index when its source field is deleted
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **Sparse indexes can be exited** (#533). Through `@jaypie/fabric` 0.3.12,
|
|
10
|
+
`indexEntity` drops a stale index key (for example `indexModelCategory` and
|
|
11
|
+
`indexModelCategorySk`) when its source field is absent. `updateEntity` writes
|
|
12
|
+
the entity with a full PUT, so deleting `category` and updating removes the
|
|
13
|
+
row from `indexModelCategory`.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.37
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: LambdaRequest provides rawHeaders; createLambdaStreamHandler runs outside Lambda and honors name
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`rawHeaders`, `rawTrailers`, `trailers` on `LambdaRequest`** (#532).
|
|
10
|
+
`rawHeaders` is the flat `[name, value, ...]` list Node's `IncomingMessage`
|
|
11
|
+
guarantees, repeating a name per value for multi-value headers.
|
|
12
|
+
`@hono/node-server`-based handlers, including `mcpExpressHandler`, now work
|
|
13
|
+
under `createLambdaHandler`.
|
|
14
|
+
- **`host` fallback**. When an event carries no `host` header,
|
|
15
|
+
`requestContext.domainName` supplies it.
|
|
16
|
+
- **`createLambdaStreamHandler` guards `awslambda`** (#534). Outside the Lambda
|
|
17
|
+
runtime it returns the plain `(event, responseStream, context)` handler rather
|
|
18
|
+
than throwing `ReferenceError` at import. Response header writes are guarded
|
|
19
|
+
the same way.
|
|
20
|
+
- **`name` option** labels unhandled error logs in both `createLambdaHandler`
|
|
21
|
+
and `createLambdaStreamHandler`.
|
|
22
|
+
- **Explicit status on an empty return** (#539). A controller that calls
|
|
23
|
+
`res.status(code)` and returns nothing responds with that code and an empty
|
|
24
|
+
body, instead of 204 or an "Illegal call to res.end()" warning. Without an
|
|
25
|
+
explicit `res.status()`, an empty return is still 204. `expressStreamHandler`
|
|
26
|
+
flushes headers before the controller runs, so the rule does not apply there.
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
expressHandler(async (req, res) => {
|
|
30
|
+
res.status(202);
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- Tests cover `logBody` and `sensitiveHeaders` on `expressStreamHandler` (#515).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.3.12
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: populateIndexKeys removes stale sparse index keys; createMcpServerFromSuite accepts a services allowlist
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`services` allowlist** (#539). `createMcpServerFromSuite` accepts
|
|
10
|
+
`services?: string[]` to expose a subset of a suite. The new
|
|
11
|
+
`selectServiceFunctions(suite, { services })` export holds the shared
|
|
12
|
+
selection logic.
|
|
13
|
+
|
|
14
|
+
- **Stale sparse index keys are removed** (#533). When a partition key source
|
|
15
|
+
field is missing, `populateIndexKeys` deletes the index key and its `Sk`
|
|
16
|
+
companion instead of preserving whatever the entity carried in. When only a
|
|
17
|
+
sort key source field is missing, it deletes the `Sk` attribute.
|
|
18
|
+
- An index with no partition key value no longer gets an orphan `Sk` attribute
|
|
19
|
+
on a new entity.
|
|
20
|
+
- The input entity is not mutated.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.101
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: Pulls @jaypie/express 1.2.37 and @jaypie/datadog 1.2.8
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`@jaypie/express` 1.2.37**: `LambdaRequest` provides `rawHeaders` (#532);
|
|
10
|
+
`createLambdaStreamHandler` runs outside Lambda and honors `name` (#534).
|
|
11
|
+
- **`@jaypie/datadog` 1.2.8**: `hasDatadogEnv` recognizes secret references
|
|
12
|
+
(#513); metric submission rejects with `BadGatewayError` (#516).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.8.153
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: SDK-free streamable HTTP handler at @jaypie/mcp/http and a services allowlist for MCP servers
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`@jaypie/mcp/http`** (#539). `mcpHttpHandler` serves any fabric
|
|
10
|
+
`ServiceSuite` as MCP streamable HTTP without `@modelcontextprotocol/sdk`.
|
|
11
|
+
Stateless JSON-RPC 2.0 on one endpoint: `initialize`, `ping`, `tools/list`,
|
|
12
|
+
`tools/call`, notifications, and batches. The `Accept` header selects a
|
|
13
|
+
buffered JSON body or an SSE stream. Notification-only requests answer 202
|
|
14
|
+
with no body and no response warning; GET and DELETE answer 405. Importing the entry loads no SDK modules.
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { mcpHttpHandler } from "@jaypie/mcp/http";
|
|
18
|
+
|
|
19
|
+
app.all("/mcp", mcpHttpHandler({ services: ["skill", "version"] }));
|
|
20
|
+
export const handler = createLambdaStreamHandler(app);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Deploy behind a `RESPONSE_STREAM` function URL for streamed responses.
|
|
24
|
+
- **`services` allowlist**. `createMcpServer`, `mcpExpressHandler`, and
|
|
25
|
+
`mcpHttpHandler` accept `services?: string[]`. Omitted exposes every service;
|
|
26
|
+
`[]` exposes none; unknown names are ignored.
|
|
27
|
+
- **Documentation** (#535, #537, #538). `EXAMPLE.md` lists the four router tools
|
|
28
|
+
and awaits `mcpExpressHandler`. Skills show `JaypieLambda` with `code` and
|
|
29
|
+
`handler`, drop the claim that `jaypie` re-exports `@jaypie/dynamodb`, document
|
|
30
|
+
sparse index removal, the Lambda adapter `host` fallback and `name` option, and
|
|
31
|
+
every Datadog key variable.
|
|
32
|
+
|
|
33
|
+
## Dependencies
|
|
34
|
+
|
|
35
|
+
`@jaypie/express`, `@jaypie/logger`, and `express` are optional peer
|
|
36
|
+
dependencies, required only by `@jaypie/mcp/http`. The CLI does not install
|
|
37
|
+
them.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.8.154
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: apigateway skill documents the JaypieDistribution zone fallback
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`apigateway` skill** lists the `JaypieDistribution` zone env fallback as
|
|
10
|
+
`CDK_ENV_API_HOSTED_ZONE` → `CDK_ENV_HOSTED_ZONE`, matching `@jaypie/constructs`
|
|
11
|
+
1.2.83.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.73
|
|
3
|
+
date: 2026-09-12
|
|
4
|
+
summary: Mock ExpressHandlerOptions and ExpressStreamHandlerOptions derive from @jaypie/express
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **Express mock option types follow the real types** (#515).
|
|
10
|
+
`ExpressHandlerOptions` and `ExpressStreamHandlerOptions` derive from
|
|
11
|
+
`@jaypie/express`, so `chaos`, `fabric`, `logBody`, `name`, `scrub`,
|
|
12
|
+
`secrets`, `sensitiveHeaders`, `unavailable`, `contentType`, and `format` are
|
|
13
|
+
typed. `locals`, `setup`, `teardown`, and `validate` keep their mock shapes.
|
|
14
|
+
- The import is type-only; `./mock` still loads without `@jaypie/express`
|
|
15
|
+
installed.
|
package/skills/apigateway.md
CHANGED
|
@@ -209,7 +209,7 @@ Two things to plan for:
|
|
|
209
209
|
|---------|------------------|-------------------|
|
|
210
210
|
| Origin | API Gateway REST | CloudFront → Function URL |
|
|
211
211
|
| Host env fallback | `CDK_ENV_API_HOST_NAME` → `CDK_ENV_API_SUBDOMAIN`+`CDK_ENV_API_HOSTED_ZONE` | Same, plus falls back to `CDK_ENV_HOSTED_ZONE` |
|
|
212
|
-
| Zone env fallback | `CDK_ENV_API_HOSTED_ZONE` | `CDK_ENV_HOSTED_ZONE` |
|
|
212
|
+
| Zone env fallback | `CDK_ENV_API_HOSTED_ZONE` | `CDK_ENV_API_HOSTED_ZONE` → `CDK_ENV_HOSTED_ZONE` |
|
|
213
213
|
| DNS | A record only | A + AAAA records |
|
|
214
214
|
| WAF | Not built in | Opt-in (`waf: true` to enable) |
|
|
215
215
|
| Security headers | Not built in | Enabled by default (`securityHeaders: false` to disable) |
|
package/skills/aws.md
CHANGED
|
@@ -235,7 +235,8 @@ Lambda functions automatically receive credentials via IAM role. Use CDK to gran
|
|
|
235
235
|
import { JaypieLambda } from "@jaypie/constructs";
|
|
236
236
|
|
|
237
237
|
const handler = new JaypieLambda(this, "Handler", {
|
|
238
|
-
|
|
238
|
+
code: "../api/dist",
|
|
239
|
+
handler: "index.handler",
|
|
239
240
|
});
|
|
240
241
|
|
|
241
242
|
// Grant S3 access
|
package/skills/cdk.md
CHANGED
|
@@ -23,8 +23,8 @@ Lambda function with Datadog tracing, logging, and error handling:
|
|
|
23
23
|
import { JaypieLambda } from "@jaypie/constructs";
|
|
24
24
|
|
|
25
25
|
const handler = new JaypieLambda(this, "ApiHandler", {
|
|
26
|
-
|
|
27
|
-
handler: "handler",
|
|
26
|
+
code: "../api/dist",
|
|
27
|
+
handler: "index.handler",
|
|
28
28
|
environment: {
|
|
29
29
|
PROJECT_ENV: "production",
|
|
30
30
|
PROJECT_KEY: "my-api",
|
|
@@ -36,7 +36,7 @@ const handler = new JaypieLambda(this, "ApiHandler", {
|
|
|
36
36
|
|
|
37
37
|
#### Pre-built Code
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
`code` accepts a pre-built bundle directory (or a `lambda.Code`); `handler` is `<file>.<export>` within it:
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
new JaypieLambda(this, "Api", {
|
|
@@ -222,8 +222,8 @@ import { JaypieDynamoDb, JaypieLambda } from "@jaypie/constructs";
|
|
|
222
222
|
const table = new JaypieDynamoDb(this, "myApp");
|
|
223
223
|
|
|
224
224
|
const handler = new JaypieLambda(this, "ApiHandler", {
|
|
225
|
-
|
|
226
|
-
handler: "handler",
|
|
225
|
+
code: "../api/dist",
|
|
226
|
+
handler: "index.handler",
|
|
227
227
|
tables: [table],
|
|
228
228
|
});
|
|
229
229
|
```
|
package/skills/datadog.md
CHANGED
|
@@ -19,7 +19,8 @@ Enable Datadog tracing in CDK:
|
|
|
19
19
|
import { JaypieLambda } from "@jaypie/constructs";
|
|
20
20
|
|
|
21
21
|
const handler = new JaypieLambda(this, "Handler", {
|
|
22
|
-
|
|
22
|
+
code: "../api/dist",
|
|
23
|
+
handler: "index.handler",
|
|
23
24
|
datadogApiKeyArn: process.env.CDK_ENV_DATADOG_API_KEY_ARN,
|
|
24
25
|
environment: {
|
|
25
26
|
DD_ENV: "production",
|
|
@@ -142,9 +143,21 @@ reference never has to be written into `process.env` first.
|
|
|
142
143
|
|----------|---------|
|
|
143
144
|
| `DATADOG_API_KEY` / `DD_API_KEY` | Plain API key |
|
|
144
145
|
| `SECRET_DATADOG_API_KEY` / `DATADOG_API_KEY_ARN` / `DD_API_KEY_SECRET_ARN` | Secrets Manager ARN, resolved with `getSecret` |
|
|
145
|
-
| `DATADOG_API_KEY_SECRET` | Secrets Manager reference, resolved with `getEnvSecret` |
|
|
146
|
+
| `DATADOG_API_KEY_SECRET` / `SECRET_DD_API_KEY` / `DD_API_KEY_SECRET` | Secrets Manager reference, resolved with `getEnvSecret` |
|
|
146
147
|
| `DATADOG_APP_KEY` / `DATADOG_APPLICATION_KEY` / `DD_APP_KEY` / `DD_APPLICATION_KEY` | Application key, required by the query service |
|
|
147
148
|
|
|
149
|
+
Each application key name also accepts a `SECRET_<NAME>` or `<NAME>_SECRET`
|
|
150
|
+
reference. Precedence for the API key: an explicit `apiSecret`, then the ARN
|
|
151
|
+
variables, then an explicit `apiKey`, then `DATADOG_API_KEY` and `DD_API_KEY`
|
|
152
|
+
through `getEnvSecret`. The ARN variables stay on `getSecret` because
|
|
153
|
+
`getEnvSecret` reads a secret reference only when `AWS_SESSION_TOKEN` is set.
|
|
154
|
+
|
|
155
|
+
`hasDatadogEnv()` recognizes every one of these API key sources, references
|
|
156
|
+
included, without resolving them. `expressHandler` gates its response metric on
|
|
157
|
+
it, so a key held only in Secrets Manager still reports. On Lambda,
|
|
158
|
+
`JaypieLambda` maps `datadogApiKeyArn`, `DATADOG_API_KEY_ARN`, or `CDK_ENV_DATADOG_API_KEY_ARN` to
|
|
159
|
+
`DD_API_KEY_SECRET_ARN`.
|
|
160
|
+
|
|
148
161
|
### LLM Observability primitives
|
|
149
162
|
|
|
150
163
|
Bundler-safe access to the runtime `dd-trace` LLM Obs singleton. `dd-trace` is resolved at runtime via a computed module specifier (never bundled), so on Lambda these reach the layer-initialized singleton — a bundled copy would be a different instance whose buffer never ships.
|
package/skills/dynamodb.md
CHANGED
|
@@ -5,7 +5,7 @@ related: apikey, aws, cdk, models, vocabulary
|
|
|
5
5
|
|
|
6
6
|
# DynamoDB Patterns
|
|
7
7
|
|
|
8
|
-
Jaypie provides `@jaypie/dynamodb` for single-table DynamoDB with entity operations, GSI-based queries, hierarchical scoping, and soft delete.
|
|
8
|
+
Jaypie provides `@jaypie/dynamodb` for single-table DynamoDB with entity operations, GSI-based queries, hierarchical scoping, and soft delete. Import it directly; the `jaypie` umbrella package does not re-export it.
|
|
9
9
|
|
|
10
10
|
## Key Design
|
|
11
11
|
|
|
@@ -41,12 +41,6 @@ import {
|
|
|
41
41
|
} from "@jaypie/dynamodb";
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Or through the main package:
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
import { APEX, initClient, createEntity, queryByScope } from "jaypie";
|
|
48
|
-
```
|
|
49
|
-
|
|
50
44
|
### Client Initialization
|
|
51
45
|
|
|
52
46
|
Call `initClient()` once at startup. In Lambda, use the handler's `setup` option:
|
|
@@ -288,6 +282,8 @@ All GSIs use a composite sort key of `scope#updatedAt` (stored as `{indexName}Sk
|
|
|
288
282
|
| `indexModelType` | `{model}#{type}` (sparse) | `indexModelTypeSk` = `{scope}#{updatedAt}` | Type filtering | You need to filter by type |
|
|
289
283
|
| `indexModelXid` | `{model}#{xid}` (sparse) | `indexModelXidSk` = `{scope}#{updatedAt}` | External ID lookup | You need cross-system ID lookups |
|
|
290
284
|
|
|
285
|
+
Sparse indexes are entered and exited by their source field. Every write re-indexes the entity: when a source field (e.g., `category`) is absent, the index key (`indexModelCategory`) and its sort key (`indexModelCategorySk`) are removed from the item, so deleting the field and calling `updateEntity` takes the row out of the index.
|
|
286
|
+
|
|
291
287
|
```typescript
|
|
292
288
|
import { fabricIndex, registerModel } from "@jaypie/fabric";
|
|
293
289
|
|