@crewhaus/mcp-server 0.5.2 → 0.5.4
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/build.d.ts +10 -3
- package/dist/build.js +20 -6
- package/dist/index.js +7 -2
- package/dist/types.d.ts +13 -0
- package/package.json +2 -2
package/dist/build.d.ts
CHANGED
|
@@ -33,9 +33,16 @@ export declare function resolveSubAgentTools(subAgents: readonly McpSubAgentDesc
|
|
|
33
33
|
/** The tool names a projection will register, without building a server. */
|
|
34
34
|
export declare function computeToolNames(opts: CreateMcpServerOptions): readonly string[];
|
|
35
35
|
/** Register the projected tools onto `server`; returns their names in order. */
|
|
36
|
-
export declare function registerAgentTools(server: McpServer, opts: CreateMcpServerOptions): readonly string[];
|
|
37
|
-
/**
|
|
38
|
-
|
|
36
|
+
export declare function registerAgentTools(server: McpServer, opts: CreateMcpServerOptions, sessionId?: string): readonly string[];
|
|
37
|
+
/**
|
|
38
|
+
* Mint a fresh SDK server with the projected tools registered.
|
|
39
|
+
*
|
|
40
|
+
* `sessionId` is threaded into every {@link McpInvokeContext} this server's
|
|
41
|
+
* tools build. The SSE path mints one server PER SESSION and passes that
|
|
42
|
+
* session's id, so a projected bundle can key its own conversation state per
|
|
43
|
+
* caller; stdio passes nothing (one process, one conversation).
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildConfiguredServer(opts: CreateMcpServerOptions, sessionId?: string): {
|
|
39
46
|
readonly server: McpServer;
|
|
40
47
|
readonly toolNames: readonly string[];
|
|
41
48
|
};
|
package/dist/build.js
CHANGED
|
@@ -82,7 +82,7 @@ async function runInvoke(invoke, message, context) {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
/** Register the projected tools onto `server`; returns their names in order. */
|
|
85
|
-
export function registerAgentTools(server, opts) {
|
|
85
|
+
export function registerAgentTools(server, opts, sessionId) {
|
|
86
86
|
const agentName = opts.name ?? DEFAULT_NAME;
|
|
87
87
|
const names = [];
|
|
88
88
|
server.registerTool(CHAT_TOOL_NAME, {
|
|
@@ -90,7 +90,10 @@ export function registerAgentTools(server, opts) {
|
|
|
90
90
|
description: opts.chatToolDescription ??
|
|
91
91
|
`Send a message to the ${agentName} agent and receive its final response.`,
|
|
92
92
|
inputSchema: { message: z.string().describe("The message to send to the agent.") },
|
|
93
|
-
}, ({ message }) => runInvoke(opts.invoke, message, {
|
|
93
|
+
}, ({ message }) => runInvoke(opts.invoke, message, {
|
|
94
|
+
toolName: CHAT_TOOL_NAME,
|
|
95
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
96
|
+
}));
|
|
94
97
|
names.push(CHAT_TOOL_NAME);
|
|
95
98
|
if (resolveToolsMode(opts.tools) === "per-subagent") {
|
|
96
99
|
for (const tool of resolveSubAgentTools(opts.subAgents ?? [])) {
|
|
@@ -100,15 +103,26 @@ export function registerAgentTools(server, opts) {
|
|
|
100
103
|
inputSchema: {
|
|
101
104
|
message: z.string().describe(`The message to route to the ${tool.subAgent} sub-agent.`),
|
|
102
105
|
},
|
|
103
|
-
}, ({ message }) => runInvoke(opts.invoke, message, {
|
|
106
|
+
}, ({ message }) => runInvoke(opts.invoke, message, {
|
|
107
|
+
toolName: tool.toolName,
|
|
108
|
+
subAgent: tool.subAgent,
|
|
109
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
110
|
+
}));
|
|
104
111
|
names.push(tool.toolName);
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
return names;
|
|
108
115
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Mint a fresh SDK server with the projected tools registered.
|
|
118
|
+
*
|
|
119
|
+
* `sessionId` is threaded into every {@link McpInvokeContext} this server's
|
|
120
|
+
* tools build. The SSE path mints one server PER SESSION and passes that
|
|
121
|
+
* session's id, so a projected bundle can key its own conversation state per
|
|
122
|
+
* caller; stdio passes nothing (one process, one conversation).
|
|
123
|
+
*/
|
|
124
|
+
export function buildConfiguredServer(opts, sessionId) {
|
|
111
125
|
const server = new McpServer({ name: opts.name ?? DEFAULT_NAME, version: opts.version ?? DEFAULT_VERSION }, opts.instructions === undefined ? undefined : { instructions: opts.instructions });
|
|
112
|
-
const toolNames = registerAgentTools(server, opts);
|
|
126
|
+
const toolNames = registerAgentTools(server, opts, sessionId);
|
|
113
127
|
return { server, toolNames };
|
|
114
128
|
}
|
package/dist/index.js
CHANGED
|
@@ -60,9 +60,14 @@ function createSseServer(opts) {
|
|
|
60
60
|
await session.server.close().catch(() => { });
|
|
61
61
|
};
|
|
62
62
|
const openSession = async (request) => {
|
|
63
|
-
|
|
63
|
+
// The id is minted HERE rather than by the transport's generator so the
|
|
64
|
+
// per-session server can be built with it: a projected bundle keys its
|
|
65
|
+
// own conversation state on this, and a server built before the id
|
|
66
|
+
// existed could only ever hand every caller the same one.
|
|
67
|
+
const sessionId = randomUUID();
|
|
68
|
+
const { server } = buildConfiguredServer(opts, sessionId);
|
|
64
69
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
65
|
-
sessionIdGenerator: () =>
|
|
70
|
+
sessionIdGenerator: () => sessionId,
|
|
66
71
|
onsessioninitialized: (id) => {
|
|
67
72
|
sessions.set(id, { server, transport });
|
|
68
73
|
},
|
package/dist/types.d.ts
CHANGED
|
@@ -49,6 +49,19 @@ export declare const CHAT_TOOL_NAME = "chat";
|
|
|
49
49
|
export interface McpInvokeContext {
|
|
50
50
|
readonly toolName: string;
|
|
51
51
|
readonly subAgent?: string;
|
|
52
|
+
/**
|
|
53
|
+
* The MCP transport's session id, on the `sse` transport once the client
|
|
54
|
+
* has initialized one. Absent on `stdio` (one process, one conversation)
|
|
55
|
+
* and on the very first request of an SSE session.
|
|
56
|
+
*
|
|
57
|
+
* It exists so a bundle that projects itself can key its OWN conversation
|
|
58
|
+
* state per CALLER: a channel daemon exposing `expose.mcp` maps this onto
|
|
59
|
+
* a harness session id, so two IDEs driving the same daemon do not write
|
|
60
|
+
* into one transcript. Without it every caller collapses onto a single
|
|
61
|
+
* shared session — which is not a subtle wrong, it is one user reading
|
|
62
|
+
* another's conversation.
|
|
63
|
+
*/
|
|
64
|
+
readonly sessionId?: string;
|
|
52
65
|
}
|
|
53
66
|
/**
|
|
54
67
|
* The injected delegate: run one agent turn for `message` and resolve with the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewhaus/mcp-server",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Project a compiled bundle's turn function as an MCP server (stdio + SSE) — a chat/invoke tool plus optional per-sub-agent tools delegating to an injected invoke fn, built on @modelcontextprotocol/sdk",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"test": "bun test src"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@crewhaus/errors": "0.5.
|
|
18
|
+
"@crewhaus/errors": "0.5.4",
|
|
19
19
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
20
20
|
"zod": "^3.23.8"
|
|
21
21
|
},
|