devframe 0.6.0-beta.2 → 0.6.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.
- package/dist/adapters/build.d.mts +1 -1
- package/dist/adapters/build.mjs +2 -2
- package/dist/adapters/cli.d.mts +1 -1
- package/dist/adapters/cli.mjs +9 -6
- package/dist/adapters/dev.d.mts +9 -2
- package/dist/adapters/dev.mjs +1 -1
- package/dist/adapters/embedded.d.mts +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.mjs +1 -337
- package/dist/build-server-0jWgMrz-.mjs +338 -0
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.mjs +56 -22
- package/dist/constants.d.mts +31 -1
- package/dist/constants.mjs +33 -1
- package/dist/{context-3x_bgBgZ.mjs → context-CKJheEtf.mjs} +2 -2
- package/dist/{context-BEVByy_Z.d.mts → context-UX9qUDK7.d.mts} +1 -1
- package/dist/{dev-BaX8fLH2.mjs → dev-zC5542OV.mjs} +49 -6
- package/dist/{devframe-D-gr9sBx.d.mts → devframe-BtVHhmwM.d.mts} +76 -4
- package/dist/{dump-DoXkj4ku.mjs → dump-D09PZb7T.mjs} +14 -4
- package/dist/{hash-DFc5WwhO.mjs → hash-PAfnyu2k.mjs} +1 -1
- package/dist/helpers/vite.d.mts +1 -1
- package/dist/helpers/vite.mjs +2 -2
- package/dist/{host-h3-C5SZlk03.mjs → host-h3-Dsf-Tgwx.mjs} +37 -11
- package/dist/http-COX960WK.mjs +114 -0
- package/dist/index-ByaMT1Xp.d.mts +107 -0
- package/dist/{index-CxaPKDXX.d.mts → index-Dy6GFDRf.d.mts} +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/{launch-editor-DPfltGA4.mjs → launch-editor-DIzaS5EG.mjs} +58 -43
- package/dist/node/auth.d.mts +2 -64
- package/dist/node/auth.mjs +2 -100
- package/dist/node/hub-internals.d.mts +2 -2
- package/dist/node/hub-internals.mjs +1 -1
- package/dist/node/index.d.mts +3 -3
- package/dist/node/index.mjs +3 -3
- package/dist/recipes/interactive-auth.d.mts +53 -0
- package/dist/recipes/interactive-auth.mjs +132 -0
- package/dist/recipes/open-helpers.mjs +2 -2
- package/dist/{revoke-ENfxWkFK.mjs → revoke-BtQDKTp7.mjs} +1 -1
- package/dist/rpc/dump.mjs +1 -1
- package/dist/rpc/index.d.mts +2 -2
- package/dist/rpc/index.mjs +4 -1
- package/dist/rpc/transports/ws-client.mjs +21 -8
- package/dist/{server-Dl6TU5LE.mjs → server-CAsvfJNK.mjs} +51 -15
- package/dist/{server-rX781kz-.d.mts → server-Cfr1NrGQ.d.mts} +52 -10
- package/dist/{shared-state-D4PPieA0.mjs → shared-state-QtMas0NG.mjs} +34 -4
- package/dist/state-WX3HT5a3.mjs +101 -0
- package/dist/{storage-l2ezeend.mjs → storage-yrUZaiib.mjs} +55 -6
- package/dist/types/index.d.mts +2 -2
- package/dist/utils/crypto-token.mjs +1 -1
- package/dist/utils/events.d.mts +1 -1
- package/dist/utils/hash.mjs +1 -1
- package/dist/utils/launch-editor.mjs +1 -1
- package/dist/utils/open.mjs +1 -1
- package/dist/utils/serve-static.mjs +2 -1
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/shared-state.mjs +1 -1
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/when.d.mts +1 -1
- package/package.json +10 -9
- package/dist/{open-Dusa2Zzd.mjs → open-Deb5xmIT.mjs} +1 -1
package/dist/adapters/build.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as collectStaticRpcDump } from "../dump-
|
|
1
|
+
import { t as collectStaticRpcDump } from "../dump-D09PZb7T.mjs";
|
|
2
2
|
import { n as colors } from "../diagnostics-reporter-CsIG85Q5.mjs";
|
|
3
3
|
import { DEVFRAME_CONNECTION_META_FILENAME, DEVFRAME_RPC_DUMP_DIRNAME, DEVFRAME_RPC_DUMP_MANIFEST_FILENAME } from "../constants.mjs";
|
|
4
4
|
import { n as strictJsonStringify } from "../serialization-DpLXCy13.mjs";
|
|
5
5
|
import { n as structuredCloneStringify } from "../structured-clone-XpHLZ8nr.mjs";
|
|
6
|
-
import { n as createHostContext, t as createH3DevframeHost } from "../host-h3-
|
|
6
|
+
import { n as createHostContext, t as createH3DevframeHost } from "../host-h3-Dsf-Tgwx.mjs";
|
|
7
7
|
import { n as resolveBasePath } from "../_shared-bWRzeSa0.mjs";
|
|
8
8
|
import { existsSync } from "node:fs";
|
|
9
9
|
import { dirname, resolve } from "pathe";
|
package/dist/adapters/cli.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Dt as parseCliFlags, Et as defineCliFlags, Tt as InferCliFlags, r as DevframeDefinition, wt as CliFlagsSchema } from "../devframe-BtVHhmwM.mjs";
|
|
2
2
|
import { CAC } from "cac";
|
|
3
3
|
import { H3 } from "h3";
|
|
4
4
|
|
package/dist/adapters/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as colors } from "../diagnostics-reporter-CsIG85Q5.mjs";
|
|
2
2
|
import { createBuild } from "./build.mjs";
|
|
3
|
-
import { n as resolveDevServerPort, t as createDevServer } from "../dev-
|
|
3
|
+
import { n as resolveDevServerPort, t as createDevServer } from "../dev-zC5542OV.mjs";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import cac from "cac";
|
|
6
6
|
import { safeParse } from "valibot";
|
|
@@ -82,7 +82,7 @@ function createCli(d, options = {}) {
|
|
|
82
82
|
const defaultPort = options.defaultPort ?? d.cli?.port ?? 9999;
|
|
83
83
|
const defaultHost = d.cli?.host ?? "localhost";
|
|
84
84
|
const cli = cac(d.cli?.command ?? d.id);
|
|
85
|
-
const devCommand = cli.command("[...args]", "Start a local dev server").option("--port <port>", "Port to listen on").option("--host <host>", "Host to bind to", { default: defaultHost }).option("--open", "Open the browser on start").option("--no-open", "Do not open the browser");
|
|
85
|
+
const devCommand = cli.command("[...args]", "Start a local dev server").option("--port <port>", "Port to listen on").option("--host <host>", "Host to bind to", { default: defaultHost }).option("--open", "Open the browser on start").option("--no-open", "Do not open the browser").option("--mcp", "Expose an MCP server over HTTP at /__mcp (use --no-mcp to disable) [experimental]");
|
|
86
86
|
if (d.cli?.flags) for (const [key, schema] of Object.entries(d.cli.flags)) {
|
|
87
87
|
const optionName = flagKeyToOption(key);
|
|
88
88
|
const description = schema.description ?? "";
|
|
@@ -92,13 +92,16 @@ function createCli(d, options = {}) {
|
|
|
92
92
|
devCommand.action(async (_args, rawFlags) => {
|
|
93
93
|
const flags = resolveTypedFlags(d, rawFlags);
|
|
94
94
|
const host = flags.host ?? defaultHost;
|
|
95
|
+
const port = flags.port ?? await resolveDevServerPort(d, {
|
|
96
|
+
host,
|
|
97
|
+
defaultPort
|
|
98
|
+
});
|
|
99
|
+
const mcp = flags.mcp;
|
|
95
100
|
await createDevServer(d, {
|
|
96
101
|
host,
|
|
97
|
-
port
|
|
98
|
-
host,
|
|
99
|
-
defaultPort
|
|
100
|
-
}),
|
|
102
|
+
port,
|
|
101
103
|
flags,
|
|
104
|
+
mcp,
|
|
102
105
|
onReady: options.onReady
|
|
103
106
|
});
|
|
104
107
|
});
|
package/dist/adapters/dev.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as DevframeWsOptions, r as DevframeDefinition } from "../devframe-
|
|
2
|
-
import { n as StartedServer } from "../server-
|
|
1
|
+
import { l as DevframeWsOptions, r as DevframeDefinition, u as McpRouteOptions } from "../devframe-BtVHhmwM.mjs";
|
|
2
|
+
import { n as StartedServer } from "../server-Cfr1NrGQ.mjs";
|
|
3
3
|
import { H3 } from "h3";
|
|
4
4
|
|
|
5
5
|
//#region src/adapters/dev.d.ts
|
|
@@ -51,6 +51,13 @@ interface CreateDevServerOptions {
|
|
|
51
51
|
* sources; a string opens that relative path.
|
|
52
52
|
*/
|
|
53
53
|
openBrowser?: boolean | string;
|
|
54
|
+
/**
|
|
55
|
+
* Expose a route-based MCP server on the dev server (Streamable-HTTP).
|
|
56
|
+
* Overrides `def.cli?.mcp`; `undefined` falls through to it. `false`
|
|
57
|
+
* disables the route regardless of the definition default. See
|
|
58
|
+
* {@link McpRouteOptions}.
|
|
59
|
+
*/
|
|
60
|
+
mcp?: boolean | McpRouteOptions;
|
|
54
61
|
/**
|
|
55
62
|
* Called once the WS server is bound. Devframe stays headless
|
|
56
63
|
* otherwise — wire this if you want a startup banner.
|
package/dist/adapters/dev.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as resolveDevServerPort, t as createDevServer } from "../dev-
|
|
1
|
+
import { n as resolveDevServerPort, t as createDevServer } from "../dev-zC5542OV.mjs";
|
|
2
2
|
export { createDevServer, resolveDevServerPort };
|
package/dist/adapters/mcp.d.mts
CHANGED
package/dist/adapters/mcp.mjs
CHANGED
|
@@ -1,338 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as createHostContext } from "../host-h3-C5SZlk03.mjs";
|
|
3
|
-
import { join } from "pathe";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
import process from "node:process";
|
|
6
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
7
|
-
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
-
import { toJsonSchema } from "@valibot/to-json-schema";
|
|
9
|
-
//#region src/adapters/mcp/stringify.ts
|
|
10
|
-
/**
|
|
11
|
-
* JSON-coercing serializer for MCP text payloads.
|
|
12
|
-
*
|
|
13
|
-
* MCP carries tool results and resource reads as plain text over a
|
|
14
|
-
* JSON-RPC transport, so we cannot use the `s:`-prefixed structured-clone
|
|
15
|
-
* format the WS RPC transport falls back to for non-JSON values. Instead,
|
|
16
|
-
* we coerce common non-JSON types into JSON-friendly forms so the LLM
|
|
17
|
-
* client sees something useful instead of `[object Object]`.
|
|
18
|
-
*
|
|
19
|
-
* Coercions:
|
|
20
|
-
* - `BigInt` → `"123n"`
|
|
21
|
-
* - `Date` → ISO string (via the native `toJSON`)
|
|
22
|
-
* - `Map` → `{ __type: 'Map', entries: [[k, v], …] }`
|
|
23
|
-
* - `Set` → `{ __type: 'Set', entries: [v, …] }`
|
|
24
|
-
* - `Error` → `{ name, message, stack, cause? }` (cause recurses)
|
|
25
|
-
* - `Function` → `"[Function: name]"`
|
|
26
|
-
* - `Symbol` → `value.toString()`
|
|
27
|
-
* - cycles → `"[Circular]"`
|
|
28
|
-
*/
|
|
29
|
-
function stringifyForMcp(value) {
|
|
30
|
-
if (value === void 0) return "undefined";
|
|
31
|
-
if (typeof value === "string") return value;
|
|
32
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
33
|
-
return JSON.stringify(value, (_key, val) => {
|
|
34
|
-
if (typeof val === "bigint") return `${val}n`;
|
|
35
|
-
if (val instanceof Error) {
|
|
36
|
-
const out = {
|
|
37
|
-
name: val.name,
|
|
38
|
-
message: val.message,
|
|
39
|
-
stack: val.stack
|
|
40
|
-
};
|
|
41
|
-
if (val.cause !== void 0) out.cause = val.cause;
|
|
42
|
-
return out;
|
|
43
|
-
}
|
|
44
|
-
if (val instanceof Map) return {
|
|
45
|
-
__type: "Map",
|
|
46
|
-
entries: [...val.entries()]
|
|
47
|
-
};
|
|
48
|
-
if (val instanceof Set) return {
|
|
49
|
-
__type: "Set",
|
|
50
|
-
entries: [...val]
|
|
51
|
-
};
|
|
52
|
-
if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`;
|
|
53
|
-
if (typeof val === "symbol") return val.toString();
|
|
54
|
-
if (val !== null && typeof val === "object") {
|
|
55
|
-
if (seen.has(val)) return "[Circular]";
|
|
56
|
-
seen.add(val);
|
|
57
|
-
}
|
|
58
|
-
return val;
|
|
59
|
-
}, 2);
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Format a thrown value for an MCP `isError` text payload. Surfaces the
|
|
63
|
-
* `Error.name`/`message`, and one level of `cause.message` so context
|
|
64
|
-
* isn't dropped silently.
|
|
65
|
-
*/
|
|
66
|
-
function formatMcpError(error) {
|
|
67
|
-
if (!(error instanceof Error)) return String(error);
|
|
68
|
-
const cause = error.cause;
|
|
69
|
-
const causeText = cause instanceof Error ? ` (cause: ${cause.message})` : cause !== void 0 ? ` (cause: ${String(cause)})` : "";
|
|
70
|
-
return `${error.name}: ${error.message}${causeText}`;
|
|
71
|
-
}
|
|
72
|
-
//#endregion
|
|
73
|
-
//#region src/adapters/mcp/to-json-schema.ts
|
|
74
|
-
const FALLBACK_OBJECT_SCHEMA = Object.freeze({
|
|
75
|
-
type: "object",
|
|
76
|
-
additionalProperties: true
|
|
77
|
-
});
|
|
78
|
-
/**
|
|
79
|
-
* Convert a valibot return schema to JSON Schema.
|
|
80
|
-
* @internal
|
|
81
|
-
*/
|
|
82
|
-
function valibotReturnToJsonSchema(schema) {
|
|
83
|
-
if (!schema) return void 0;
|
|
84
|
-
try {
|
|
85
|
-
return toJsonSchema(schema);
|
|
86
|
-
} catch {
|
|
87
|
-
return FALLBACK_OBJECT_SCHEMA;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Convert positional RPC args schemas to a single MCP-friendly object
|
|
92
|
-
* schema. When the RPC declares `args: [v.object(...)]`, unwrap the
|
|
93
|
-
* single-object schema directly (nicer agent UX than `{ arg0: {...} }`).
|
|
94
|
-
*
|
|
95
|
-
* Returns `undefined` when there are no args (the MCP SDK treats this
|
|
96
|
-
* as `{ type: 'object', properties: {} }`).
|
|
97
|
-
* @internal
|
|
98
|
-
*/
|
|
99
|
-
function valibotArgsToJsonSchema(args) {
|
|
100
|
-
if (!args || args.length === 0) return {
|
|
101
|
-
schema: {
|
|
102
|
-
type: "object",
|
|
103
|
-
properties: {}
|
|
104
|
-
},
|
|
105
|
-
unwrapped: false
|
|
106
|
-
};
|
|
107
|
-
if (args.length === 1) {
|
|
108
|
-
const inner = safeToJsonSchema(args[0]);
|
|
109
|
-
if (isObjectJsonSchema(inner)) return {
|
|
110
|
-
schema: inner,
|
|
111
|
-
unwrapped: true
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
const properties = {};
|
|
115
|
-
const required = [];
|
|
116
|
-
for (let i = 0; i < args.length; i++) {
|
|
117
|
-
const key = `arg${i}`;
|
|
118
|
-
properties[key] = safeToJsonSchema(args[i]);
|
|
119
|
-
required.push(key);
|
|
120
|
-
}
|
|
121
|
-
return {
|
|
122
|
-
schema: {
|
|
123
|
-
type: "object",
|
|
124
|
-
properties,
|
|
125
|
-
required,
|
|
126
|
-
additionalProperties: false
|
|
127
|
-
},
|
|
128
|
-
unwrapped: false
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
function safeToJsonSchema(schema) {
|
|
132
|
-
try {
|
|
133
|
-
return toJsonSchema(schema);
|
|
134
|
-
} catch {
|
|
135
|
-
return FALLBACK_OBJECT_SCHEMA;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function isObjectJsonSchema(value) {
|
|
139
|
-
return !!value && typeof value === "object" && value.type === "object";
|
|
140
|
-
}
|
|
141
|
-
//#endregion
|
|
142
|
-
//#region src/adapters/mcp/build-server.ts
|
|
143
|
-
/**
|
|
144
|
-
* Wire an MCP {@link Server} to a devframe context. Returns the server
|
|
145
|
-
* plus a disposal function for the subscriptions it sets up. The
|
|
146
|
-
* transport is the caller's responsibility — `createMcpServer` connects
|
|
147
|
-
* stdio; tests can connect an {@link InMemoryTransport} instead.
|
|
148
|
-
*
|
|
149
|
-
* @internal
|
|
150
|
-
*/
|
|
151
|
-
function buildMcpServerFromContext(ctx, options) {
|
|
152
|
-
const server = new Server({
|
|
153
|
-
name: options.serverName,
|
|
154
|
-
version: options.serverVersion
|
|
155
|
-
}, { capabilities: {
|
|
156
|
-
tools: { listChanged: true },
|
|
157
|
-
resources: { listChanged: true }
|
|
158
|
-
} });
|
|
159
|
-
registerToolHandlers(server, ctx);
|
|
160
|
-
registerResourceHandlers(server, ctx, options.exposeSharedState);
|
|
161
|
-
const notify = (method) => {
|
|
162
|
-
server.notification({ method }).catch(() => {});
|
|
163
|
-
};
|
|
164
|
-
const offManifest = ctx.agent.events.on("agent:manifest:changed", () => {
|
|
165
|
-
notify("notifications/tools/list_changed");
|
|
166
|
-
notify("notifications/resources/list_changed");
|
|
167
|
-
});
|
|
168
|
-
const offKeyAdded = ctx.rpc.sharedState.onKeyAdded(() => {
|
|
169
|
-
notify("notifications/resources/list_changed");
|
|
170
|
-
});
|
|
171
|
-
return {
|
|
172
|
-
server,
|
|
173
|
-
dispose: () => {
|
|
174
|
-
offManifest();
|
|
175
|
-
offKeyAdded();
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Build an MCP server over the agent surface of a devframe definition.
|
|
181
|
-
* Currently supports `stdio` transport only.
|
|
182
|
-
*
|
|
183
|
-
* @experimental The agent-native surface is experimental and may change
|
|
184
|
-
* without a major version bump until it stabilizes.
|
|
185
|
-
*/
|
|
186
|
-
async function createMcpServer(definition, options = {}) {
|
|
187
|
-
const transport = options.transport ?? "stdio";
|
|
188
|
-
if (transport !== "stdio") throw diagnostics.DF0017({
|
|
189
|
-
transport,
|
|
190
|
-
reason: "Only stdio transport is supported in this release."
|
|
191
|
-
});
|
|
192
|
-
const ctx = await createHostContext({
|
|
193
|
-
cwd: process.cwd(),
|
|
194
|
-
mode: "dev",
|
|
195
|
-
host: {
|
|
196
|
-
mountStatic: () => {},
|
|
197
|
-
resolveOrigin: () => "mcp://devframe",
|
|
198
|
-
getStorageDir: (scope) => scope === "workspace" ? join(process.cwd(), `node_modules/.${definition.id}/devframe`) : join(homedir(), `.${definition.id}/devframe`)
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
await definition.setup(ctx);
|
|
202
|
-
const { server, dispose } = buildMcpServerFromContext(ctx, {
|
|
203
|
-
serverName: options.serverName ?? `${definition.id} (devframe)`,
|
|
204
|
-
serverVersion: options.serverVersion ?? definition.version ?? "0.0.0",
|
|
205
|
-
exposeSharedState: options.exposeSharedState ?? true
|
|
206
|
-
});
|
|
207
|
-
const { startStdioTransport } = await import("../transports-BmDVn4SF.mjs");
|
|
208
|
-
let stop;
|
|
209
|
-
try {
|
|
210
|
-
stop = await startStdioTransport(server);
|
|
211
|
-
} catch (error) {
|
|
212
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
213
|
-
throw diagnostics.DF0017({
|
|
214
|
-
transport,
|
|
215
|
-
reason,
|
|
216
|
-
cause: error
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
options.onReady?.({ transport: "stdio" });
|
|
220
|
-
return { async stop() {
|
|
221
|
-
dispose();
|
|
222
|
-
await stop();
|
|
223
|
-
} };
|
|
224
|
-
}
|
|
225
|
-
function registerToolHandlers(server, ctx) {
|
|
226
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
227
|
-
return { tools: ctx.agent.list().tools.map((tool) => projectTool(tool, ctx)) };
|
|
228
|
-
});
|
|
229
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
230
|
-
const { name, arguments: args } = request.params;
|
|
231
|
-
try {
|
|
232
|
-
return { content: [{
|
|
233
|
-
type: "text",
|
|
234
|
-
text: stringifyForMcp(await ctx.agent.invoke(name, args ?? {}))
|
|
235
|
-
}] };
|
|
236
|
-
} catch (error) {
|
|
237
|
-
return {
|
|
238
|
-
isError: true,
|
|
239
|
-
content: [{
|
|
240
|
-
type: "text",
|
|
241
|
-
text: `Error invoking "${name}": ${formatMcpError(error)}`
|
|
242
|
-
}]
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
function registerResourceHandlers(server, ctx, exposeSharedState) {
|
|
248
|
-
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
249
|
-
const resources = ctx.agent.list().resources.map((resource) => ({
|
|
250
|
-
uri: resource.uri,
|
|
251
|
-
name: resource.name,
|
|
252
|
-
description: resource.description,
|
|
253
|
-
mimeType: resource.mimeType
|
|
254
|
-
}));
|
|
255
|
-
if (exposeSharedState !== false) {
|
|
256
|
-
const filter = typeof exposeSharedState === "function" ? exposeSharedState : () => true;
|
|
257
|
-
for (const key of ctx.rpc.sharedState.keys()) {
|
|
258
|
-
if (!filter(key)) continue;
|
|
259
|
-
resources.push({
|
|
260
|
-
uri: `devframe://state/${encodeURIComponent(key)}`,
|
|
261
|
-
name: key,
|
|
262
|
-
description: `Shared state: ${key}`,
|
|
263
|
-
mimeType: "application/json"
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return { resources };
|
|
268
|
-
});
|
|
269
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
270
|
-
const { uri } = request.params;
|
|
271
|
-
const parsed = parseResourceUri(uri);
|
|
272
|
-
if (parsed.kind === "resource") {
|
|
273
|
-
const content = await ctx.agent.read(parsed.id);
|
|
274
|
-
return { contents: [{
|
|
275
|
-
uri,
|
|
276
|
-
mimeType: content.mimeType ?? "application/json",
|
|
277
|
-
text: content.text ?? stringifyForMcp(content.json)
|
|
278
|
-
}] };
|
|
279
|
-
}
|
|
280
|
-
if (parsed.kind === "state") return { contents: [{
|
|
281
|
-
uri,
|
|
282
|
-
mimeType: "application/json",
|
|
283
|
-
text: stringifyForMcp((await ctx.rpc.sharedState.get(parsed.key)).value())
|
|
284
|
-
}] };
|
|
285
|
-
throw new Error(`[devframe/mcp] unknown resource URI "${uri}"`);
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
function projectTool(tool, ctx) {
|
|
289
|
-
const inputSchema = tool.inputSchema ?? computeInputSchema(tool, ctx);
|
|
290
|
-
const outputSchema = tool.outputSchema ?? computeOutputSchema(tool, ctx);
|
|
291
|
-
return {
|
|
292
|
-
name: tool.id,
|
|
293
|
-
title: tool.title,
|
|
294
|
-
description: tool.description,
|
|
295
|
-
inputSchema,
|
|
296
|
-
...outputSchema ? { outputSchema } : {},
|
|
297
|
-
annotations: {
|
|
298
|
-
title: tool.title,
|
|
299
|
-
readOnlyHint: tool.safety === "read",
|
|
300
|
-
destructiveHint: tool.safety === "destructive"
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
function computeInputSchema(tool, ctx) {
|
|
305
|
-
if (tool.kind !== "rpc" || !tool.rpcName) return {
|
|
306
|
-
type: "object",
|
|
307
|
-
properties: {}
|
|
308
|
-
};
|
|
309
|
-
const def = ctx.rpc.definitions.get(tool.rpcName);
|
|
310
|
-
if (!def) return {
|
|
311
|
-
type: "object",
|
|
312
|
-
properties: {}
|
|
313
|
-
};
|
|
314
|
-
const args = def.args;
|
|
315
|
-
return valibotArgsToJsonSchema(args).schema;
|
|
316
|
-
}
|
|
317
|
-
function computeOutputSchema(tool, ctx) {
|
|
318
|
-
if (tool.kind !== "rpc" || !tool.rpcName) return void 0;
|
|
319
|
-
const def = ctx.rpc.definitions.get(tool.rpcName);
|
|
320
|
-
if (!def) return void 0;
|
|
321
|
-
return valibotReturnToJsonSchema(def.returns);
|
|
322
|
-
}
|
|
323
|
-
function parseResourceUri(uri) {
|
|
324
|
-
const match = uri.match(/^devframe:\/\/(resource|state)\/(.+)$/);
|
|
325
|
-
if (!match) return { kind: "unknown" };
|
|
326
|
-
const [, kind, rest] = match;
|
|
327
|
-
const decoded = decodeURIComponent(rest);
|
|
328
|
-
if (kind === "resource") return {
|
|
329
|
-
kind: "resource",
|
|
330
|
-
id: decoded
|
|
331
|
-
};
|
|
332
|
-
return {
|
|
333
|
-
kind: "state",
|
|
334
|
-
key: decoded
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
//#endregion
|
|
1
|
+
import { n as createMcpServer } from "../build-server-0jWgMrz-.mjs";
|
|
338
2
|
export { createMcpServer };
|