@noodleseed/one 0.191.0 → 0.192.1
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/node_modules/@noodle-borg/assistant-gateway/dist/assistant-guide.d.ts +3 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-guide.js +7 -8
- package/node_modules/@noodle-borg/protocol/dist/v2/handler.d.ts +2 -6
- package/node_modules/@noodle-borg/protocol/dist/v2/handler.js +2 -156
- package/node_modules/@noodle-borg/protocol/dist/v2/platform-handler.d.ts +15 -0
- package/node_modules/@noodle-borg/protocol/dist/v2/platform-handler.js +157 -0
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { type ToolAuthorizationCaller } from '@noodle-borg/protocol';
|
|
|
3
3
|
import { type SurfaceCapabilityRef } from './artifact-projection.js';
|
|
4
4
|
/** Model-context budget for the embedded assistant's compact product workflow projection. */
|
|
5
5
|
export declare const ASSISTANT_GUIDE_MAX_BYTES: number;
|
|
6
|
-
export type AssistantGuideUnavailableReason = 'package_unavailable'
|
|
6
|
+
export type AssistantGuideUnavailableReason = 'package_unavailable';
|
|
7
7
|
/**
|
|
8
8
|
* What a guide over {@link ASSISTANT_GUIDE_MAX_BYTES} gave up to fit. Size never removes the guide:
|
|
9
9
|
* purpose, use cases, boundaries, and one index line per workflow always survive, so a business with
|
|
@@ -88,6 +88,8 @@ export declare function assistantModelToolOncePerSession(tool: ArtifactTool): bo
|
|
|
88
88
|
/**
|
|
89
89
|
* Build bounded product guidance from structured App Package data, never from rendered host files.
|
|
90
90
|
* Workflows are atomic: if one step is unavailable to this model, the entire workflow is omitted.
|
|
91
|
+
* When none survives (an anonymous visitor, a tool-less turn), the guide still carries purpose, use
|
|
92
|
+
* cases, and boundaries: they must be safe for every audience, so the caller's identity never removes them.
|
|
91
93
|
*
|
|
92
94
|
* Over budget, detail is shed in one fixed order until the guide fits: first every example, then each
|
|
93
95
|
* workflow's intent and steps, last authored workflow first, leaving its index line (id, title, when to
|
|
@@ -125,6 +125,8 @@ function normalizeVisibilityText(value) {
|
|
|
125
125
|
/**
|
|
126
126
|
* Build bounded product guidance from structured App Package data, never from rendered host files.
|
|
127
127
|
* Workflows are atomic: if one step is unavailable to this model, the entire workflow is omitted.
|
|
128
|
+
* When none survives (an anonymous visitor, a tool-less turn), the guide still carries purpose, use
|
|
129
|
+
* cases, and boundaries: they must be safe for every audience, so the caller's identity never removes them.
|
|
128
130
|
*
|
|
129
131
|
* Over budget, detail is shed in one fixed order until the guide fits: first every example, then each
|
|
130
132
|
* workflow's intent and steps, last authored workflow first, leaving its index line (id, title, when to
|
|
@@ -133,14 +135,12 @@ function normalizeVisibilityText(value) {
|
|
|
133
135
|
export function projectAssistantGuide(input) {
|
|
134
136
|
const parsed = appPackageArtifactV1Schema.safeParse(input.appPackage);
|
|
135
137
|
if (!parsed.success)
|
|
136
|
-
return unavailable
|
|
138
|
+
return { status: 'unavailable', reason: 'package_unavailable' };
|
|
137
139
|
const projected = projectAppPackageCapabilities(parsed.data, {
|
|
138
140
|
tools: input.modelTools.map((tool) => tool.name),
|
|
139
141
|
resources: [],
|
|
140
142
|
prompts: [],
|
|
141
|
-
});
|
|
142
|
-
if (projected === undefined)
|
|
143
|
-
return unavailable('no_complete_workflow');
|
|
143
|
+
}) ?? { ...parsed.data, skill: { ...parsed.data.skill, workflows: [], examples: [] } };
|
|
144
144
|
const workflows = projected.skill.workflows;
|
|
145
145
|
const workflowIds = workflows.map((workflow) => workflow.id);
|
|
146
146
|
let content = renderGuide(projected, { examples: true, indexOnly: [] });
|
|
@@ -179,7 +179,9 @@ function renderGuide(appPackage, shed) {
|
|
|
179
179
|
`Product purpose: ${oneLine(skill.description)}`,
|
|
180
180
|
'Use when:',
|
|
181
181
|
...skill.useWhen.map((value) => `- ${oneLine(value)}`),
|
|
182
|
-
|
|
182
|
+
...(workflows.length === 0
|
|
183
|
+
? ['No product workflows are available in this conversation.']
|
|
184
|
+
: ['Workflows:']),
|
|
183
185
|
];
|
|
184
186
|
for (const workflow of workflows) {
|
|
185
187
|
if (indexOnly.has(workflow.id)) {
|
|
@@ -252,7 +254,4 @@ function behaviorFacts(behavior) {
|
|
|
252
254
|
function oneLine(value) {
|
|
253
255
|
return value.replace(/\s+/g, ' ').trim();
|
|
254
256
|
}
|
|
255
|
-
function unavailable(reason) {
|
|
256
|
-
return { status: 'unavailable', reason };
|
|
257
|
-
}
|
|
258
257
|
//# sourceMappingURL=assistant-guide.js.map
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { McpHttpHandler } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { ProtocolRequestContext, ServedArtifact } from '../sdk-server.js';
|
|
3
|
-
|
|
3
|
+
export { createPlatformDualEraMcpHandler } from './platform-handler.js';
|
|
4
4
|
/**
|
|
5
5
|
* The single Noodle MCP entry: SDK-owned era classification/dispatch with a narrow Noodle response seam.
|
|
6
6
|
*/
|
|
7
7
|
export declare function createDualEraMcpHandler(target: ServedArtifact, context?: ProtocolRequestContext): McpHttpHandler;
|
|
8
|
-
/** Platform-wide SDK v2 handler used by artifact and first-party MCP surfaces alike. */
|
|
9
|
-
export declare function createPlatformDualEraMcpHandler(factory: McpServerFactory, platformOptions?: {
|
|
10
|
-
readonly protocolMode?: McpProtocolMode;
|
|
11
|
-
}): McpHttpHandler;
|
|
12
8
|
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { createMcpHandler, isLegacyRequest, } from '@modelcontextprotocol/server';
|
|
3
2
|
import { notify } from '../observation.js';
|
|
4
3
|
import { RequestStateManager, requestStateSecretBox } from '../request-state.js';
|
|
4
|
+
import { createPlatformDualEraMcpHandlerInternal } from './platform-handler.js';
|
|
5
5
|
import { protocolErrorObservation } from './response-observation.js';
|
|
6
6
|
import { buildDualEraMcpServer } from './server.js';
|
|
7
|
-
|
|
7
|
+
export { createPlatformDualEraMcpHandler } from './platform-handler.js';
|
|
8
8
|
/**
|
|
9
9
|
* The single Noodle MCP entry: SDK-owned era classification/dispatch with a narrow Noodle response seam.
|
|
10
10
|
*/
|
|
@@ -24,40 +24,6 @@ export function createDualEraMcpHandler(target, context = {}) {
|
|
|
24
24
|
finish: (request) => requestObservations.delete(request),
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
/** Platform-wide SDK v2 handler used by artifact and first-party MCP surfaces alike. */
|
|
28
|
-
export function createPlatformDualEraMcpHandler(factory, platformOptions = {}) {
|
|
29
|
-
return createPlatformDualEraMcpHandlerInternal(factory, platformOptions);
|
|
30
|
-
}
|
|
31
|
-
function createPlatformDualEraMcpHandlerInternal(factory, platformOptions = {}, hooks) {
|
|
32
|
-
const sdkHandler = createMcpHandler(factory, { legacy: 'stateless' });
|
|
33
|
-
return {
|
|
34
|
-
...sdkHandler,
|
|
35
|
-
fetch: async (request, options) => {
|
|
36
|
-
hooks?.begin(request);
|
|
37
|
-
try {
|
|
38
|
-
const legacy = await isLegacyRequest(request.clone(), options?.parsedBody);
|
|
39
|
-
const requestBody = await readRequestBody(request, options?.parsedBody);
|
|
40
|
-
if (platformOptions.protocolMode === 'legacy-only' && !legacy) {
|
|
41
|
-
return new Response(JSON.stringify({
|
|
42
|
-
jsonrpc: '2.0',
|
|
43
|
-
id: requestId(requestBody),
|
|
44
|
-
error: { code: -32601, message: 'Method not found' },
|
|
45
|
-
}), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
46
|
-
}
|
|
47
|
-
const response = await sdkHandler.fetch(request, {
|
|
48
|
-
...options,
|
|
49
|
-
...(requestBody === undefined ? {} : { parsedBody: requestBody }),
|
|
50
|
-
});
|
|
51
|
-
const shaped = await shapeNoodleResponse(response, requestBody, legacy);
|
|
52
|
-
await observeResponseBestEffort(hooks, request, requestBody, shaped);
|
|
53
|
-
return shaped;
|
|
54
|
-
}
|
|
55
|
-
finally {
|
|
56
|
-
hooks?.finish(request);
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
27
|
const processRequestState = new RequestStateManager(requestStateSecretBox(randomBytes(32)));
|
|
62
28
|
function requestProtocolContext(context, requestContext) {
|
|
63
29
|
return {
|
|
@@ -79,26 +45,6 @@ function observedProtocolContext(context, requestContext, requestObservations) {
|
|
|
79
45
|
},
|
|
80
46
|
};
|
|
81
47
|
}
|
|
82
|
-
async function observeResponseBestEffort(hooks, request, requestBody, response) {
|
|
83
|
-
try {
|
|
84
|
-
await hooks?.observeResponse(request, requestBody, response);
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
// Protocol analytics must never change the response it observes.
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
async function readRequestBody(request, parsedBody) {
|
|
91
|
-
if (parsedBody !== undefined)
|
|
92
|
-
return parsedBody;
|
|
93
|
-
if (request.method.toUpperCase() !== 'POST')
|
|
94
|
-
return undefined;
|
|
95
|
-
try {
|
|
96
|
-
return await request.clone().json();
|
|
97
|
-
}
|
|
98
|
-
catch {
|
|
99
|
-
return undefined;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
48
|
async function readResponseBody(response) {
|
|
103
49
|
const contentType = response.headers.get('content-type');
|
|
104
50
|
if (contentType?.split(';', 1)[0]?.trim().toLowerCase() !== 'application/json')
|
|
@@ -110,104 +56,4 @@ async function readResponseBody(response) {
|
|
|
110
56
|
return undefined;
|
|
111
57
|
}
|
|
112
58
|
}
|
|
113
|
-
async function shapeNoodleResponse(response, requestBody, legacy) {
|
|
114
|
-
const contentType = response.headers.get('content-type');
|
|
115
|
-
if (legacy && contentType?.split(';', 1)[0]?.trim().toLowerCase() === 'text/event-stream') {
|
|
116
|
-
const eventStream = await response.text();
|
|
117
|
-
const eventData = firstServerSentEventData(eventStream);
|
|
118
|
-
if (eventData === undefined)
|
|
119
|
-
return copyResponse(response, eventStream);
|
|
120
|
-
const headers = new Headers(response.headers);
|
|
121
|
-
headers.set('content-type', 'application/json');
|
|
122
|
-
return shapeNoodleResponse(new Response(eventData, {
|
|
123
|
-
status: response.status,
|
|
124
|
-
statusText: response.statusText,
|
|
125
|
-
headers,
|
|
126
|
-
}), requestBody, legacy);
|
|
127
|
-
}
|
|
128
|
-
if (contentType?.split(';', 1)[0]?.trim().toLowerCase() !== 'application/json')
|
|
129
|
-
return response;
|
|
130
|
-
const text = await response.text();
|
|
131
|
-
let body;
|
|
132
|
-
try {
|
|
133
|
-
body = JSON.parse(text);
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
return copyResponse(response, text);
|
|
137
|
-
}
|
|
138
|
-
if (!isRecord(body))
|
|
139
|
-
return copyResponse(response, text);
|
|
140
|
-
const method = requestMethod(requestBody);
|
|
141
|
-
const id = requestId(requestBody);
|
|
142
|
-
const error = isRecord(body.error) ? body.error : undefined;
|
|
143
|
-
const result = isRecord(body.result) ? body.result : undefined;
|
|
144
|
-
let status = response.status;
|
|
145
|
-
if (!legacy && method === 'initialize') {
|
|
146
|
-
status = 400;
|
|
147
|
-
body = {
|
|
148
|
-
jsonrpc: '2.0',
|
|
149
|
-
error: {
|
|
150
|
-
code: -32022,
|
|
151
|
-
message: 'Unsupported protocol version',
|
|
152
|
-
data: {
|
|
153
|
-
supported: [...SERVED_MCP_PROTOCOL_VERSIONS],
|
|
154
|
-
requested: '2026-07-28',
|
|
155
|
-
},
|
|
156
|
-
},
|
|
157
|
-
id,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
else if (error?.code === -32022 && isRecord(error.data)) {
|
|
161
|
-
error.data.supported = [...SERVED_MCP_PROTOCOL_VERSIONS];
|
|
162
|
-
}
|
|
163
|
-
else if (legacy && error !== undefined && typeof error.code === 'number') {
|
|
164
|
-
const code = method === 'resources/read' && error.code === -32602 ? -32002 : error.code;
|
|
165
|
-
const rawMessage = typeof error.message === 'string'
|
|
166
|
-
? error.message.replace(/^MCP error -?\d+: /, '')
|
|
167
|
-
: 'Protocol error';
|
|
168
|
-
body = {
|
|
169
|
-
jsonrpc: '2.0',
|
|
170
|
-
id,
|
|
171
|
-
error: {
|
|
172
|
-
code,
|
|
173
|
-
message: `MCP error ${code}: ${rawMessage}`,
|
|
174
|
-
...(error.data === undefined ? {} : { data: error.data }),
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
else if (!legacy && method === 'server/discover' && result !== undefined) {
|
|
179
|
-
result.supportedVersions = [...SERVED_MCP_PROTOCOL_VERSIONS];
|
|
180
|
-
}
|
|
181
|
-
return copyResponse(response, JSON.stringify(body), status);
|
|
182
|
-
}
|
|
183
|
-
function copyResponse(response, body, status = response.status) {
|
|
184
|
-
return new Response(body, {
|
|
185
|
-
status,
|
|
186
|
-
statusText: response.statusText,
|
|
187
|
-
headers: response.headers,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
function firstServerSentEventData(body) {
|
|
191
|
-
for (const event of body.split(/\r?\n\r?\n/)) {
|
|
192
|
-
const data = event
|
|
193
|
-
.split(/\r?\n/)
|
|
194
|
-
.filter((line) => line.startsWith('data:'))
|
|
195
|
-
.map((line) => line.slice(5).trimStart())
|
|
196
|
-
.join('\n');
|
|
197
|
-
if (data.length > 0)
|
|
198
|
-
return data;
|
|
199
|
-
}
|
|
200
|
-
return undefined;
|
|
201
|
-
}
|
|
202
|
-
function requestMethod(body) {
|
|
203
|
-
return isRecord(body) && typeof body.method === 'string' ? body.method : undefined;
|
|
204
|
-
}
|
|
205
|
-
function requestId(body) {
|
|
206
|
-
if (!isRecord(body))
|
|
207
|
-
return null;
|
|
208
|
-
return typeof body.id === 'string' || typeof body.id === 'number' ? body.id : null;
|
|
209
|
-
}
|
|
210
|
-
function isRecord(value) {
|
|
211
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
212
|
-
}
|
|
213
59
|
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type McpHttpHandler, type McpServerFactory } from '@modelcontextprotocol/server';
|
|
2
|
+
import { type McpProtocolMode } from './versions.js';
|
|
3
|
+
/** Platform-wide SDK v2 handler used by artifact and first-party MCP surfaces alike. */
|
|
4
|
+
export declare function createPlatformDualEraMcpHandler(factory: McpServerFactory, platformOptions?: {
|
|
5
|
+
readonly protocolMode?: McpProtocolMode;
|
|
6
|
+
}): McpHttpHandler;
|
|
7
|
+
export interface PlatformHandlerHooks {
|
|
8
|
+
readonly begin: (request: Request) => void;
|
|
9
|
+
readonly observeResponse: (request: Request, requestBody: unknown, response: Response) => void | Promise<void>;
|
|
10
|
+
readonly finish: (request: Request) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function createPlatformDualEraMcpHandlerInternal(factory: McpServerFactory, platformOptions?: {
|
|
13
|
+
readonly protocolMode?: McpProtocolMode;
|
|
14
|
+
}, hooks?: PlatformHandlerHooks): McpHttpHandler;
|
|
15
|
+
//# sourceMappingURL=platform-handler.d.ts.map
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { createMcpHandler, isLegacyRequest, } from '@modelcontextprotocol/server';
|
|
2
|
+
import { SERVED_MCP_PROTOCOL_VERSIONS } from './versions.js';
|
|
3
|
+
/** Platform-wide SDK v2 handler used by artifact and first-party MCP surfaces alike. */
|
|
4
|
+
export function createPlatformDualEraMcpHandler(factory, platformOptions = {}) {
|
|
5
|
+
return createPlatformDualEraMcpHandlerInternal(factory, platformOptions);
|
|
6
|
+
}
|
|
7
|
+
export function createPlatformDualEraMcpHandlerInternal(factory, platformOptions = {}, hooks) {
|
|
8
|
+
const sdkHandler = createMcpHandler(factory, { legacy: 'stateless' });
|
|
9
|
+
return {
|
|
10
|
+
...sdkHandler,
|
|
11
|
+
fetch: async (request, options) => {
|
|
12
|
+
hooks?.begin(request);
|
|
13
|
+
try {
|
|
14
|
+
const legacy = await isLegacyRequest(request.clone(), options?.parsedBody);
|
|
15
|
+
const requestBody = await readRequestBody(request, options?.parsedBody);
|
|
16
|
+
if (platformOptions.protocolMode === 'legacy-only' && !legacy) {
|
|
17
|
+
return new Response(JSON.stringify({
|
|
18
|
+
jsonrpc: '2.0',
|
|
19
|
+
id: requestId(requestBody),
|
|
20
|
+
error: { code: -32601, message: 'Method not found' },
|
|
21
|
+
}), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
22
|
+
}
|
|
23
|
+
const response = await sdkHandler.fetch(request, {
|
|
24
|
+
...options,
|
|
25
|
+
...(requestBody === undefined ? {} : { parsedBody: requestBody }),
|
|
26
|
+
});
|
|
27
|
+
const shaped = await shapeNoodleResponse(response, requestBody, legacy);
|
|
28
|
+
await observeResponseBestEffort(hooks, request, requestBody, shaped);
|
|
29
|
+
return shaped;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
hooks?.finish(request);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function observeResponseBestEffort(hooks, request, requestBody, response) {
|
|
38
|
+
try {
|
|
39
|
+
await hooks?.observeResponse(request, requestBody, response);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Protocol analytics must never change the response it observes.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function readRequestBody(request, parsedBody) {
|
|
46
|
+
if (parsedBody !== undefined)
|
|
47
|
+
return parsedBody;
|
|
48
|
+
if (request.method.toUpperCase() !== 'POST')
|
|
49
|
+
return undefined;
|
|
50
|
+
try {
|
|
51
|
+
return await request.clone().json();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function shapeNoodleResponse(response, requestBody, legacy) {
|
|
58
|
+
const contentType = response.headers.get('content-type');
|
|
59
|
+
if (legacy && contentType?.split(';', 1)[0]?.trim().toLowerCase() === 'text/event-stream') {
|
|
60
|
+
const eventStream = await response.text();
|
|
61
|
+
const eventData = firstServerSentEventData(eventStream);
|
|
62
|
+
if (eventData === undefined)
|
|
63
|
+
return copyResponse(response, eventStream);
|
|
64
|
+
const headers = new Headers(response.headers);
|
|
65
|
+
headers.set('content-type', 'application/json');
|
|
66
|
+
return shapeNoodleResponse(new Response(eventData, {
|
|
67
|
+
status: response.status,
|
|
68
|
+
statusText: response.statusText,
|
|
69
|
+
headers,
|
|
70
|
+
}), requestBody, legacy);
|
|
71
|
+
}
|
|
72
|
+
if (contentType?.split(';', 1)[0]?.trim().toLowerCase() !== 'application/json')
|
|
73
|
+
return response;
|
|
74
|
+
const text = await response.text();
|
|
75
|
+
let body;
|
|
76
|
+
try {
|
|
77
|
+
body = JSON.parse(text);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return copyResponse(response, text);
|
|
81
|
+
}
|
|
82
|
+
if (!isRecord(body))
|
|
83
|
+
return copyResponse(response, text);
|
|
84
|
+
const method = requestMethod(requestBody);
|
|
85
|
+
const id = requestId(requestBody);
|
|
86
|
+
const error = isRecord(body.error) ? body.error : undefined;
|
|
87
|
+
const result = isRecord(body.result) ? body.result : undefined;
|
|
88
|
+
let status = response.status;
|
|
89
|
+
if (!legacy && method === 'initialize') {
|
|
90
|
+
status = 400;
|
|
91
|
+
body = {
|
|
92
|
+
jsonrpc: '2.0',
|
|
93
|
+
error: {
|
|
94
|
+
code: -32022,
|
|
95
|
+
message: 'Unsupported protocol version',
|
|
96
|
+
data: {
|
|
97
|
+
supported: [...SERVED_MCP_PROTOCOL_VERSIONS],
|
|
98
|
+
requested: '2026-07-28',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
id,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
else if (error?.code === -32022 && isRecord(error.data)) {
|
|
105
|
+
error.data.supported = [...SERVED_MCP_PROTOCOL_VERSIONS];
|
|
106
|
+
}
|
|
107
|
+
else if (legacy && error !== undefined && typeof error.code === 'number') {
|
|
108
|
+
const code = method === 'resources/read' && error.code === -32602 ? -32002 : error.code;
|
|
109
|
+
const rawMessage = typeof error.message === 'string'
|
|
110
|
+
? error.message.replace(/^MCP error -?\d+: /, '')
|
|
111
|
+
: 'Protocol error';
|
|
112
|
+
body = {
|
|
113
|
+
jsonrpc: '2.0',
|
|
114
|
+
id,
|
|
115
|
+
error: {
|
|
116
|
+
code,
|
|
117
|
+
message: `MCP error ${code}: ${rawMessage}`,
|
|
118
|
+
...(error.data === undefined ? {} : { data: error.data }),
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
else if (!legacy && method === 'server/discover' && result !== undefined) {
|
|
123
|
+
result.supportedVersions = [...SERVED_MCP_PROTOCOL_VERSIONS];
|
|
124
|
+
}
|
|
125
|
+
return copyResponse(response, JSON.stringify(body), status);
|
|
126
|
+
}
|
|
127
|
+
function copyResponse(response, body, status = response.status) {
|
|
128
|
+
return new Response(body, {
|
|
129
|
+
status,
|
|
130
|
+
statusText: response.statusText,
|
|
131
|
+
headers: response.headers,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function firstServerSentEventData(body) {
|
|
135
|
+
for (const event of body.split(/\r?\n\r?\n/)) {
|
|
136
|
+
const data = event
|
|
137
|
+
.split(/\r?\n/)
|
|
138
|
+
.filter((line) => line.startsWith('data:'))
|
|
139
|
+
.map((line) => line.slice(5).trimStart())
|
|
140
|
+
.join('\n');
|
|
141
|
+
if (data.length > 0)
|
|
142
|
+
return data;
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
function requestMethod(body) {
|
|
147
|
+
return isRecord(body) && typeof body.method === 'string' ? body.method : undefined;
|
|
148
|
+
}
|
|
149
|
+
function requestId(body) {
|
|
150
|
+
if (!isRecord(body))
|
|
151
|
+
return null;
|
|
152
|
+
return typeof body.id === 'string' || typeof body.id === 'number' ? body.id : null;
|
|
153
|
+
}
|
|
154
|
+
function isRecord(value) {
|
|
155
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=platform-handler.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/one",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.192.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
|
|
6
6
|
"license": "Apache-2.0",
|