@malloy-publisher/server 0.0.226 → 0.0.227
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 +2 -11
- package/dist/package_load_worker.mjs +86 -24
- package/dist/server.mjs +655 -6994
- package/package.json +1 -4
- package/src/health.ts +3 -8
- package/src/mcp/error_messages.ts +8 -37
- package/src/mcp/handler_utils.ts +10 -129
- package/src/mcp/mcp_constants.ts +0 -16
- package/src/mcp/{agent_server.protocol.spec.ts → server.protocol.spec.ts} +14 -12
- package/src/mcp/server.ts +29 -37
- package/src/mcp/skills/build_skills_bundle.ts +1 -1
- package/src/mcp/skills/skills_bundle.json +1 -1
- package/src/mcp/tools/docs_search_tool.ts +1 -1
- package/src/mcp/tools/execute_query_tool.ts +2 -2
- package/src/mcp/tools/get_context_eval.ts +3 -3
- package/src/mcp/tools/get_context_tool.spec.ts +196 -1
- package/src/mcp/tools/get_context_tool.ts +165 -67
- package/src/package_load/package_load_pool.ts +3 -0
- package/src/package_load/package_load_worker.ts +68 -24
- package/src/package_load/protocol.ts +16 -0
- package/src/package_load/rpc_wait_accountant.spec.ts +109 -0
- package/src/package_load/rpc_wait_accountant.ts +76 -0
- package/src/package_load_metrics.spec.ts +114 -0
- package/src/package_load_metrics.ts +127 -0
- package/src/pg_helpers.spec.ts +2 -206
- package/src/pg_helpers.ts +4 -120
- package/src/server.ts +0 -16
- package/src/service/environment.ts +1 -1
- package/src/service/package.ts +82 -42
- package/src/test_helpers/metrics_harness.ts +40 -0
- package/tests/harness/mcp_test_setup.ts +1 -1
- package/tests/integration/mcp/mcp_transport.integration.spec.ts +7 -31
- package/tests/integration/watch-mode/watch_mode.integration.spec.ts +0 -6
- package/dxt/malloy_bridge.py +0 -354
- package/dxt/manifest.json +0 -22
- package/src/dto/connection.dto.spec.ts +0 -186
- package/src/dto/connection.dto.ts +0 -308
- package/src/dto/index.ts +0 -2
- package/src/dto/package.dto.spec.ts +0 -42
- package/src/dto/package.dto.ts +0 -27
- package/src/dto/validate.spec.ts +0 -76
- package/src/dto/validate.ts +0 -31
- package/src/ducklake_version.spec.ts +0 -43
- package/src/ducklake_version.ts +0 -26
- package/src/mcp/agent_server.spec.ts +0 -18
- package/src/mcp/agent_server.ts +0 -144
- package/src/mcp/prompts/handlers.ts +0 -84
- package/src/mcp/prompts/index.ts +0 -11
- package/src/mcp/prompts/prompt_definitions.ts +0 -160
- package/src/mcp/prompts/prompt_service.ts +0 -67
- package/src/mcp/prompts/utils.ts +0 -62
- package/src/mcp/resource_metadata.ts +0 -47
- package/src/mcp/resources/environment_resource.ts +0 -187
- package/src/mcp/resources/model_resource.ts +0 -155
- package/src/mcp/resources/notebook_resource.ts +0 -137
- package/src/mcp/resources/package_resource.ts +0 -373
- package/src/mcp/resources/query_resource.ts +0 -122
- package/src/mcp/resources/source_resource.ts +0 -141
- package/src/mcp/resources/view_resource.ts +0 -136
- package/src/mcp/tools/discovery_tools.ts +0 -280
- package/src/storage/BaseRepository.ts +0 -31
- package/src/storage/StorageManager.mock.ts +0 -50
- package/tests/harness/e2e.ts +0 -96
- package/tests/harness/mocks.ts +0 -39
- package/tests/harness/uris.ts +0 -31
- package/tests/integration/mcp/mcp_resource.integration.spec.ts +0 -655
- package/tests/integration/mcp/setup.spec.ts +0 -5
- package/tests/unit/mcp/prompt_definitions.test.ts +0 -102
- package/tests/unit/mcp/prompt_happy.test.ts +0 -51
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
McpServer,
|
|
3
|
-
ResourceTemplate,
|
|
4
|
-
} from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
-
import type { ListResourcesResult } from "@modelcontextprotocol/sdk/types.js"; // Needed for list return type
|
|
6
|
-
import { logger } from "../../logger";
|
|
7
|
-
import { EnvironmentStore } from "../../service/environment_store";
|
|
8
|
-
import { getInternalError, getNotFoundError } from "../error_messages"; // Needed for error handling in list AND get
|
|
9
|
-
import { handleResourceGet, McpGetResourceError } from "../handler_utils";
|
|
10
|
-
import { RESOURCE_METADATA } from "../resource_metadata";
|
|
11
|
-
|
|
12
|
-
// Define an interface for the package object augmented with environment name
|
|
13
|
-
interface PackageWithEnvironment {
|
|
14
|
-
name?: string;
|
|
15
|
-
// Add other relevant package properties if needed
|
|
16
|
-
environmentName: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Registers the Malloy environment resource type with the MCP server (URI scheme malloy://environment/...).
|
|
21
|
-
* Lists packages across environments and resolves environment metadata on read.
|
|
22
|
-
*/
|
|
23
|
-
export function registerEnvironmentResource(
|
|
24
|
-
mcpServer: McpServer,
|
|
25
|
-
environmentStore: EnvironmentStore,
|
|
26
|
-
): void {
|
|
27
|
-
mcpServer.resource(
|
|
28
|
-
"environment",
|
|
29
|
-
new ResourceTemplate("malloy://environment/{environmentName}", {
|
|
30
|
-
/**
|
|
31
|
-
* Handles ListResources requests.
|
|
32
|
-
* If environmentName is specified, lists packages for that environment (only 'home' supported).
|
|
33
|
-
* If environmentName is not specified (general ListResources call), lists packages for the default 'home' environment.
|
|
34
|
-
*/
|
|
35
|
-
list: async (/* extra: ListEnvironmentExtra - Deleted */): Promise<ListResourcesResult> => {
|
|
36
|
-
logger.info(
|
|
37
|
-
"[MCP LOG] Entering ListResources (environment) handler (listing ALL packages)...",
|
|
38
|
-
);
|
|
39
|
-
// Ignore parameters from 'extra' as URI path params aren't passed to list handlers.
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const allEnvironments =
|
|
43
|
-
await environmentStore.listEnvironments();
|
|
44
|
-
logger.info(
|
|
45
|
-
`[MCP LOG] Found ${allEnvironments.length} environments defined.`,
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const packagePromises = allEnvironments.map(async (env) => {
|
|
49
|
-
try {
|
|
50
|
-
logger.info(
|
|
51
|
-
`[MCP LOG] Getting environment '${env.name}' to list its packages...`,
|
|
52
|
-
);
|
|
53
|
-
const environmentInstance =
|
|
54
|
-
await environmentStore.getEnvironment(env.name!, false);
|
|
55
|
-
const packages = await environmentInstance.listPackages();
|
|
56
|
-
logger.info(
|
|
57
|
-
`[MCP LOG] Found ${packages.length} packages in environment '${env.name}'.`,
|
|
58
|
-
);
|
|
59
|
-
// Return packages along with their environment name for URI construction
|
|
60
|
-
return packages.map((pkg) => ({
|
|
61
|
-
...pkg,
|
|
62
|
-
environmentName: env.name,
|
|
63
|
-
}));
|
|
64
|
-
} catch (environmentError) {
|
|
65
|
-
logger.error(
|
|
66
|
-
`[MCP Server Error] Error getting/listing packages for environment ${env.name}:`,
|
|
67
|
-
{ error: environmentError },
|
|
68
|
-
);
|
|
69
|
-
return []; // Return empty array for this environment on error
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const results = await Promise.allSettled(packagePromises);
|
|
74
|
-
const allPackagesWithEnvironmentName = results
|
|
75
|
-
.filter((result) => result.status === "fulfilled")
|
|
76
|
-
.flatMap(
|
|
77
|
-
(result) =>
|
|
78
|
-
(
|
|
79
|
-
result as PromiseFulfilledResult<
|
|
80
|
-
PackageWithEnvironment[]
|
|
81
|
-
>
|
|
82
|
-
).value,
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
logger.info(
|
|
86
|
-
`[MCP LOG] Total packages found across all environments: ${allPackagesWithEnvironmentName.length}`,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
const packageMetadata = RESOURCE_METADATA.package;
|
|
90
|
-
const mappedResources = allPackagesWithEnvironmentName.map(
|
|
91
|
-
(pkg) => {
|
|
92
|
-
const name = pkg.name || "unknown";
|
|
93
|
-
// Construct URI using the package's specific environmentName
|
|
94
|
-
const uri = `malloy://environment/${pkg.environmentName}/package/${name}`;
|
|
95
|
-
return {
|
|
96
|
-
uri: uri,
|
|
97
|
-
name: name,
|
|
98
|
-
type: "package",
|
|
99
|
-
description: packageMetadata?.description as
|
|
100
|
-
| string
|
|
101
|
-
| undefined,
|
|
102
|
-
metadata: packageMetadata,
|
|
103
|
-
};
|
|
104
|
-
},
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
logger.info(
|
|
108
|
-
`[MCP LOG] ListResources (environment): Returning ${mappedResources.length} package resources.`,
|
|
109
|
-
);
|
|
110
|
-
return {
|
|
111
|
-
resources: mappedResources,
|
|
112
|
-
};
|
|
113
|
-
} catch (error) {
|
|
114
|
-
// Catch errors from environmentStore.listEnvironments() itself
|
|
115
|
-
logger.error(`[MCP Server Error] Error listing environments:`, {
|
|
116
|
-
error,
|
|
117
|
-
});
|
|
118
|
-
const errorDetails = getInternalError(
|
|
119
|
-
`ListResources (environment - initial list)`,
|
|
120
|
-
error,
|
|
121
|
-
);
|
|
122
|
-
logger.error("MCP ListResources (environment) error:", {
|
|
123
|
-
error: errorDetails.message,
|
|
124
|
-
});
|
|
125
|
-
logger.info(
|
|
126
|
-
"[MCP LOG] ListResources (environment): Returning empty on error listing environments.",
|
|
127
|
-
);
|
|
128
|
-
return { resources: [] };
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
}),
|
|
132
|
-
/** Handles GetResource requests for Malloy environments */
|
|
133
|
-
(uri, params) =>
|
|
134
|
-
handleResourceGet(
|
|
135
|
-
uri,
|
|
136
|
-
params,
|
|
137
|
-
"environment",
|
|
138
|
-
async ({ environmentName }: { environmentName?: unknown }) => {
|
|
139
|
-
logger.info(
|
|
140
|
-
`[MCP LOG] Entering GetResource (environment) handler for environmentName: ${environmentName}`,
|
|
141
|
-
);
|
|
142
|
-
// Validate environment name parameter
|
|
143
|
-
if (typeof environmentName !== "string") {
|
|
144
|
-
logger.error(
|
|
145
|
-
"[MCP LOG] GetResource (environment): Invalid environment name param.",
|
|
146
|
-
);
|
|
147
|
-
throw new Error("Invalid environment name parameter.");
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
logger.info(
|
|
152
|
-
`[MCP LOG] GetResource: Getting environment '${environmentName}'...`,
|
|
153
|
-
);
|
|
154
|
-
// Get the environment instance, but we might not need its metadata directly
|
|
155
|
-
await environmentStore.getEnvironment(environmentName, false);
|
|
156
|
-
// Construct the definition object expected by the test
|
|
157
|
-
const definition = { name: environmentName };
|
|
158
|
-
logger.info(
|
|
159
|
-
`[MCP LOG] GetResource (environment): Returning definition for '${environmentName}'.`,
|
|
160
|
-
);
|
|
161
|
-
// Return the explicit definition structure
|
|
162
|
-
return definition;
|
|
163
|
-
} catch (error) {
|
|
164
|
-
logger.error(
|
|
165
|
-
`[MCP LOG] GetResource (environment): Error caught for '${environmentName}':`,
|
|
166
|
-
{ error },
|
|
167
|
-
);
|
|
168
|
-
// Catch expected errors from this specific resource logic
|
|
169
|
-
if (error instanceof Error) {
|
|
170
|
-
// Use getNotFoundError for the specific environment not found case
|
|
171
|
-
// or a generic message for the invalid param case.
|
|
172
|
-
const errorDetails = getNotFoundError(
|
|
173
|
-
error.message.includes("not found")
|
|
174
|
-
? `Environment '${environmentName}'` // More specific context
|
|
175
|
-
: `Invalid environment identifier provided for URI ${uri.href}`, // Generic but informative
|
|
176
|
-
);
|
|
177
|
-
// Re-throw structured error for handleResourceGet to catch
|
|
178
|
-
throw new McpGetResourceError(errorDetails);
|
|
179
|
-
}
|
|
180
|
-
// Re-throw unexpected errors to be caught by handleResourceGet's generic handler
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
RESOURCE_METADATA.environment,
|
|
185
|
-
),
|
|
186
|
-
);
|
|
187
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
McpServer,
|
|
3
|
-
ResourceTemplate,
|
|
4
|
-
} from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
-
import { EnvironmentStore } from "../../service/environment_store";
|
|
6
|
-
import {
|
|
7
|
-
ModelNotFoundError,
|
|
8
|
-
PackageNotFoundError,
|
|
9
|
-
ModelCompilationError,
|
|
10
|
-
} from "../../errors";
|
|
11
|
-
import { handleResourceGet, McpGetResourceError } from "../handler_utils";
|
|
12
|
-
import { RESOURCE_METADATA } from "../resource_metadata";
|
|
13
|
-
import {
|
|
14
|
-
getNotFoundError,
|
|
15
|
-
getMalloyErrorDetails,
|
|
16
|
-
getInternalError,
|
|
17
|
-
} from "../error_messages";
|
|
18
|
-
import type { components } from "../../api"; // Import the components type
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Registers the Malloy Model resource type with the MCP server.
|
|
22
|
-
* Handles getting details for a specific model.
|
|
23
|
-
*/
|
|
24
|
-
export function registerModelResource(
|
|
25
|
-
mcpServer: McpServer,
|
|
26
|
-
environmentStore: EnvironmentStore,
|
|
27
|
-
): void {
|
|
28
|
-
mcpServer.resource(
|
|
29
|
-
"model",
|
|
30
|
-
new ResourceTemplate(
|
|
31
|
-
"malloy://environment/{environmentName}/package/{packageName}/models/{modelPath}",
|
|
32
|
-
{ list: undefined }, // No list handler for individual models
|
|
33
|
-
),
|
|
34
|
-
/** Handles GetResource requests for specific Malloy Models */
|
|
35
|
-
(uri, params) =>
|
|
36
|
-
handleResourceGet(
|
|
37
|
-
uri,
|
|
38
|
-
params,
|
|
39
|
-
"model",
|
|
40
|
-
async ({
|
|
41
|
-
environmentName,
|
|
42
|
-
packageName,
|
|
43
|
-
modelPath,
|
|
44
|
-
}: {
|
|
45
|
-
environmentName?: unknown;
|
|
46
|
-
packageName?: unknown;
|
|
47
|
-
modelPath?: unknown;
|
|
48
|
-
}) => {
|
|
49
|
-
try {
|
|
50
|
-
// Validate all parameters
|
|
51
|
-
if (typeof environmentName !== "string") {
|
|
52
|
-
throw new Error("Invalid environment name parameter.");
|
|
53
|
-
}
|
|
54
|
-
if (typeof packageName !== "string") {
|
|
55
|
-
throw new Error("Invalid package name parameter.");
|
|
56
|
-
}
|
|
57
|
-
if (typeof modelPath !== "string") {
|
|
58
|
-
throw new Error("Invalid model path parameter.");
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// *** UPDATED LOGIC using EnvironmentStore ***
|
|
62
|
-
// getEnvironment can throw EnvironmentNotFoundError (though unlikely if name is 'home')
|
|
63
|
-
const environment = await environmentStore.getEnvironment(
|
|
64
|
-
environmentName,
|
|
65
|
-
false,
|
|
66
|
-
);
|
|
67
|
-
// getPackage can throw PackageNotFoundError
|
|
68
|
-
const pkg = await environment.getPackage(packageName, false);
|
|
69
|
-
// getModel is SYNCHRONOUS
|
|
70
|
-
const modelInstance = pkg.getModel(modelPath);
|
|
71
|
-
// *** END UPDATED LOGIC ***
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
!modelInstance ||
|
|
75
|
-
modelInstance.getModelType() === "notebook"
|
|
76
|
-
) {
|
|
77
|
-
// Explicitly throw the expected error if not found or wrong type
|
|
78
|
-
throw new ModelNotFoundError(modelPath);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// modelInstance.getModel() is ASYNC and can throw ModelCompilationError
|
|
82
|
-
const compiledModelDefinition: components["schemas"]["CompiledModel"] =
|
|
83
|
-
await modelInstance.getModel();
|
|
84
|
-
|
|
85
|
-
// Strip implicit filters from agent-facing responses
|
|
86
|
-
if (compiledModelDefinition.sources) {
|
|
87
|
-
for (const source of compiledModelDefinition.sources) {
|
|
88
|
-
if (source.filters) {
|
|
89
|
-
source.filters = source.filters.filter(
|
|
90
|
-
(f) => !f.implicit,
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return compiledModelDefinition;
|
|
97
|
-
} catch (error) {
|
|
98
|
-
let errorDetails;
|
|
99
|
-
// Provide specific context for error messages
|
|
100
|
-
// Use validated string parameters here
|
|
101
|
-
const safeEnvironmentName =
|
|
102
|
-
typeof environmentName === "string"
|
|
103
|
-
? environmentName
|
|
104
|
-
: "unknown";
|
|
105
|
-
const safePackageName =
|
|
106
|
-
typeof packageName === "string" ? packageName : "unknown";
|
|
107
|
-
const safeModelPath =
|
|
108
|
-
typeof modelPath === "string" ? modelPath : "unknown";
|
|
109
|
-
|
|
110
|
-
const notFoundContext = `Model '${safeModelPath}' in package '${safePackageName}' for environment '${safeEnvironmentName}'`;
|
|
111
|
-
const malloyErrorContext = `${safeEnvironmentName}/${safePackageName}/${safeModelPath}`;
|
|
112
|
-
|
|
113
|
-
if (error instanceof PackageNotFoundError) {
|
|
114
|
-
// Package not found during getPackage call
|
|
115
|
-
errorDetails = getNotFoundError(
|
|
116
|
-
`Package '${safePackageName}' in environment '${safeEnvironmentName}'`,
|
|
117
|
-
);
|
|
118
|
-
} else if (error instanceof ModelNotFoundError) {
|
|
119
|
-
// Model not found (either from getModel or type check)
|
|
120
|
-
errorDetails = getNotFoundError(notFoundContext);
|
|
121
|
-
} else if (error instanceof ModelCompilationError) {
|
|
122
|
-
// Compilation error when fetching model definition
|
|
123
|
-
errorDetails = getMalloyErrorDetails(
|
|
124
|
-
"GetResource (model)",
|
|
125
|
-
malloyErrorContext,
|
|
126
|
-
error,
|
|
127
|
-
);
|
|
128
|
-
} else if (error instanceof Error) {
|
|
129
|
-
// Catch invalid param errors or other generic errors
|
|
130
|
-
// Provide a clearer message differentiating param errors
|
|
131
|
-
if (error.message.includes("parameter")) {
|
|
132
|
-
errorDetails = getNotFoundError(
|
|
133
|
-
`Invalid identifier parameter provided for URI ${uri.href}: ${error.message}`,
|
|
134
|
-
);
|
|
135
|
-
} else {
|
|
136
|
-
errorDetails = getInternalError(
|
|
137
|
-
"GetResource (model) - Unexpected Error",
|
|
138
|
-
error,
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
// Fallback for truly unexpected non-Error throws
|
|
143
|
-
errorDetails = getInternalError(
|
|
144
|
-
"GetResource (model)",
|
|
145
|
-
error,
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
// Wrap and re-throw for handleResourceGet
|
|
149
|
-
throw new McpGetResourceError(errorDetails);
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
RESOURCE_METADATA.model,
|
|
153
|
-
),
|
|
154
|
-
);
|
|
155
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
McpServer,
|
|
3
|
-
ResourceTemplate,
|
|
4
|
-
} from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
-
import { URL } from "url";
|
|
6
|
-
import type { components } from "../../api"; // Need this for CompiledModel type
|
|
7
|
-
import {
|
|
8
|
-
ModelCompilationError,
|
|
9
|
-
ModelNotFoundError,
|
|
10
|
-
PackageNotFoundError,
|
|
11
|
-
} from "../../errors";
|
|
12
|
-
import { logger } from "../../logger";
|
|
13
|
-
import { EnvironmentStore } from "../../service/environment_store";
|
|
14
|
-
import {
|
|
15
|
-
getInternalError,
|
|
16
|
-
getMalloyErrorDetails,
|
|
17
|
-
getNotFoundError,
|
|
18
|
-
} from "../error_messages";
|
|
19
|
-
import { handleResourceGet, McpGetResourceError } from "../handler_utils";
|
|
20
|
-
import { RESOURCE_METADATA } from "../resource_metadata";
|
|
21
|
-
|
|
22
|
-
// Define the expected parameter types
|
|
23
|
-
type NotebookParams = {
|
|
24
|
-
environmentName?: unknown;
|
|
25
|
-
packageName?: unknown;
|
|
26
|
-
notebookName?: unknown;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Registers the Malloy Notebook resource type.
|
|
31
|
-
* Handles getting details for a specific notebook.
|
|
32
|
-
*/
|
|
33
|
-
export function registerNotebookResource(
|
|
34
|
-
mcpServer: McpServer,
|
|
35
|
-
environmentStore: EnvironmentStore,
|
|
36
|
-
): void {
|
|
37
|
-
mcpServer.resource(
|
|
38
|
-
"notebook",
|
|
39
|
-
new ResourceTemplate(
|
|
40
|
-
"malloy://environment/{environmentName}/package/{packageName}/notebooks/{notebookName}",
|
|
41
|
-
{ list: undefined }, // Listing notebooks is not supported via this template
|
|
42
|
-
),
|
|
43
|
-
(uri, params) =>
|
|
44
|
-
handleResourceGet(
|
|
45
|
-
uri,
|
|
46
|
-
params as NotebookParams,
|
|
47
|
-
"notebook",
|
|
48
|
-
async (
|
|
49
|
-
{ environmentName, packageName, notebookName }: NotebookParams,
|
|
50
|
-
uri: URL,
|
|
51
|
-
) => {
|
|
52
|
-
if (
|
|
53
|
-
typeof environmentName !== "string" ||
|
|
54
|
-
typeof packageName !== "string" ||
|
|
55
|
-
typeof notebookName !== "string"
|
|
56
|
-
) {
|
|
57
|
-
throw new Error("Invalid parameters for notebook resource.");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let modelInstance;
|
|
61
|
-
try {
|
|
62
|
-
const environment = await environmentStore.getEnvironment(
|
|
63
|
-
environmentName,
|
|
64
|
-
false,
|
|
65
|
-
);
|
|
66
|
-
const pkg = await environment.getPackage(packageName, false);
|
|
67
|
-
// Get the model instance using the notebookName as the path
|
|
68
|
-
modelInstance = pkg.getModel(notebookName);
|
|
69
|
-
|
|
70
|
-
// Check if it exists and is actually a notebook
|
|
71
|
-
if (
|
|
72
|
-
!modelInstance ||
|
|
73
|
-
modelInstance.getModelType() !== "notebook"
|
|
74
|
-
) {
|
|
75
|
-
const isNotebookError =
|
|
76
|
-
modelInstance?.getModelType() !== "notebook";
|
|
77
|
-
const errorDetails = getNotFoundError(
|
|
78
|
-
`Notebook '${notebookName}' in package '${packageName}' environment '${environmentName}'${
|
|
79
|
-
isNotebookError ? " (not a .malloynb file)" : ""
|
|
80
|
-
}`,
|
|
81
|
-
);
|
|
82
|
-
throw new McpGetResourceError(errorDetails);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Now try to get the actual notebook content
|
|
86
|
-
const notebookContent: components["schemas"]["RawNotebook"] =
|
|
87
|
-
await modelInstance.getNotebook();
|
|
88
|
-
return notebookContent;
|
|
89
|
-
} catch (error) {
|
|
90
|
-
if (error instanceof McpGetResourceError) {
|
|
91
|
-
throw error; // Re-throw if already formatted by checks above
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Handle specific errors like PackageNotFoundError or ModelCompilationError
|
|
95
|
-
if (error instanceof PackageNotFoundError) {
|
|
96
|
-
throw new McpGetResourceError(
|
|
97
|
-
getNotFoundError(
|
|
98
|
-
`Package '${packageName}' in environment '${environmentName}'`,
|
|
99
|
-
),
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
// Handle ModelCompilationError from modelInstance.getModel()
|
|
103
|
-
if (error instanceof ModelCompilationError) {
|
|
104
|
-
const malloyErrorContext = `${environmentName}/${packageName}/${notebookName}`;
|
|
105
|
-
throw new McpGetResourceError(
|
|
106
|
-
getMalloyErrorDetails(
|
|
107
|
-
"GetResource (notebook compilation)",
|
|
108
|
-
malloyErrorContext,
|
|
109
|
-
error,
|
|
110
|
-
),
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
// Handle ModelNotFoundError specifically from pkg.getModel()
|
|
114
|
-
if (error instanceof ModelNotFoundError) {
|
|
115
|
-
throw new McpGetResourceError(
|
|
116
|
-
getNotFoundError(
|
|
117
|
-
`Notebook '${notebookName}' not found in package '${packageName}' environment '${environmentName}'`,
|
|
118
|
-
),
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Handle other unexpected errors
|
|
123
|
-
logger.error(
|
|
124
|
-
`[MCP Server Error] Error fetching notebook '${notebookName}' from ${uri.href}:`,
|
|
125
|
-
{ error },
|
|
126
|
-
);
|
|
127
|
-
const fallbackErrorDetails = getInternalError(
|
|
128
|
-
`GetResource (notebook: ${uri.href})`,
|
|
129
|
-
error,
|
|
130
|
-
);
|
|
131
|
-
throw new McpGetResourceError(fallbackErrorDetails);
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
RESOURCE_METADATA.notebook,
|
|
135
|
-
),
|
|
136
|
-
);
|
|
137
|
-
}
|