@yolk-sdk/mcp 0.1.0-canary.113 → 0.1.0-canary.115
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 +9 -0
- package/dist/client/protocol.d.mts +5 -5
- package/dist/client/protocol.d.mts.map +1 -1
- package/dist/client/protocol.mjs +25 -8
- package/dist/client/protocol.mjs.map +1 -1
- package/dist/server/server.d.mts.map +1 -1
- package/dist/server/server.mjs +14 -1
- package/dist/server/server.mjs.map +1 -1
- package/package.json +3 -3
- package/src/client/protocol.ts +33 -15
- package/src/server/server.ts +15 -0
package/README.md
CHANGED
|
@@ -189,6 +189,15 @@ const step = Effect.gen(function* () {
|
|
|
189
189
|
- Legacy-era elicitation (a server-initiated request answered while the call's stream is open) is
|
|
190
190
|
not supported; resuming against a legacy connection fails with `unsupported_era`.
|
|
191
191
|
|
|
192
|
+
### Files in tool results
|
|
193
|
+
|
|
194
|
+
The client maps embedded resource blobs in tool results to `FilePart`s (named from the URI), so
|
|
195
|
+
`resolveTools({ files })` stores them and the model sees a `fileId` label instead of base64
|
|
196
|
+
([ADR 0009](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0009-file-claim-check.md));
|
|
197
|
+
embedded text stays text, and images and audio stay viewable parts. When adapting Yolk tools into
|
|
198
|
+
an MCP server, an inline `FilePart` leaves as an embedded resource blob and a captured one as its
|
|
199
|
+
label.
|
|
200
|
+
|
|
192
201
|
## Connect to a local stdio server
|
|
193
202
|
|
|
194
203
|
Node hosts can use the convenience wrappers from `client/node`:
|
|
@@ -172,9 +172,9 @@ declare const decodeJsonRpcResponse: (input: unknown, options?: import("effect/S
|
|
|
172
172
|
declare const decodeToolsListResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Effect.Effect<{
|
|
173
173
|
readonly tools: readonly {
|
|
174
174
|
readonly name: string;
|
|
175
|
-
readonly title?: string | undefined;
|
|
176
175
|
readonly outputSchema?: unknown;
|
|
177
176
|
readonly inputSchema?: Schema.JsonObject | undefined;
|
|
177
|
+
readonly title?: string | undefined;
|
|
178
178
|
readonly description?: string | undefined;
|
|
179
179
|
readonly annotations?: {
|
|
180
180
|
readonly [x: string]: unknown;
|
|
@@ -182,11 +182,11 @@ declare const decodeToolsListResult: (input: unknown, options?: import("effect/S
|
|
|
182
182
|
}[];
|
|
183
183
|
}, Schema.SchemaError, never>;
|
|
184
184
|
declare const decodeToolCallResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Effect.Effect<{
|
|
185
|
-
readonly isError?: boolean | undefined;
|
|
186
|
-
readonly structuredContent?: unknown;
|
|
187
185
|
readonly content?: readonly {
|
|
188
186
|
readonly [x: string]: unknown;
|
|
189
187
|
}[] | undefined;
|
|
188
|
+
readonly isError?: boolean | undefined;
|
|
189
|
+
readonly structuredContent?: unknown;
|
|
190
190
|
}, Schema.SchemaError, never>;
|
|
191
191
|
declare const encodeJsonRpcMessage: (server: string, message: JsonRpcRequest | JsonRpcNotification) => Effect.Effect<string, McpError, never>;
|
|
192
192
|
declare const decodeJsonRpcResponseFromJson: (server: string, text: string) => Effect.Effect<{
|
|
@@ -203,13 +203,13 @@ declare const decodeJsonRpcResponseFromJson: (server: string, text: string) => E
|
|
|
203
203
|
};
|
|
204
204
|
}, McpError, never>;
|
|
205
205
|
declare const decodeJsonRpcMessageFromJson: (server: string, text: string) => Effect.Effect<{
|
|
206
|
+
readonly method: string;
|
|
206
207
|
readonly id: string | number;
|
|
207
208
|
readonly jsonrpc: "2.0";
|
|
208
|
-
readonly method: string;
|
|
209
209
|
readonly params?: unknown;
|
|
210
210
|
} | {
|
|
211
|
-
readonly jsonrpc: "2.0";
|
|
212
211
|
readonly method: string;
|
|
212
|
+
readonly jsonrpc: "2.0";
|
|
213
213
|
readonly params?: unknown;
|
|
214
214
|
}, McpError, never>;
|
|
215
215
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.mts","names":[],"sources":["../../src/client/protocol.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"protocol.d.mts","names":[],"sources":["../../src/client/protocol.ts"],"mappings":"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"}
|
package/dist/client/protocol.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpError } from "./errors.mjs";
|
|
2
2
|
import { Array, Effect, Option, Predicate } from "effect";
|
|
3
3
|
import * as Schema from "effect/Schema";
|
|
4
|
-
import { AudioPart, ImagePart, TextPart, ToolDef, ToolJsonSchemaObject, ToolResult, decodeToolJsonSchemaObject, inlineBase64Source } from "@yolk-sdk/agent/protocol";
|
|
4
|
+
import { AudioPart, FilePart, ImagePart, TextPart, ToolDef, ToolJsonSchemaObject, ToolResult, decodeToolJsonSchemaObject, inlineBase64Source } from "@yolk-sdk/agent/protocol";
|
|
5
5
|
//#region src/client/protocol.ts
|
|
6
6
|
const latestMcpProtocolVersion = "2026-07-28";
|
|
7
7
|
const legacyMcpProtocolVersion = "2024-11-05";
|
|
@@ -175,12 +175,29 @@ const fallbackTextForContentBlock = (block) => {
|
|
|
175
175
|
default: return `Unsupported MCP ${type} content.`;
|
|
176
176
|
}
|
|
177
177
|
};
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
178
|
+
const resourceFilename = (uri) => {
|
|
179
|
+
const segments = (uri.split(/[?#]/u, 1)[0] ?? "").split("/").filter((part) => part.length > 0);
|
|
180
|
+
const segment = segments[segments.length - 1];
|
|
181
|
+
if (segment === void 0 || segment.endsWith(":")) return void 0;
|
|
182
|
+
try {
|
|
183
|
+
return decodeURIComponent(segment);
|
|
184
|
+
} catch {
|
|
185
|
+
return segment;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const embeddedResourcePart = (block) => Schema.decodeUnknownOption(EmbeddedResourceContentBlock)(block).pipe(Option.flatMap(({ resource }) => {
|
|
189
|
+
if (resource.text !== void 0) return Option.some(TextPart.make({ text: resource.text }));
|
|
190
|
+
if (resource.blob === void 0) return Option.none();
|
|
191
|
+
const mimeType = resource.mimeType ?? "application/octet-stream";
|
|
192
|
+
const filename = resource.uri === void 0 ? void 0 : resourceFilename(resource.uri);
|
|
193
|
+
return Option.some(filename === void 0 ? FilePart.make({
|
|
194
|
+
source: inlineBase64Source(resource.blob),
|
|
195
|
+
mimeType
|
|
196
|
+
}) : FilePart.make({
|
|
197
|
+
source: inlineBase64Source(resource.blob),
|
|
198
|
+
mimeType,
|
|
199
|
+
filename
|
|
200
|
+
}));
|
|
184
201
|
}));
|
|
185
202
|
const resourceLinkText = (block) => Schema.decodeUnknownOption(ResourceLinkContentBlock)(block).pipe(Option.map(({ name, uri }) => {
|
|
186
203
|
return `MCP resource link: ${name ?? uri} (${uri})`;
|
|
@@ -204,7 +221,7 @@ const contentPartFromBlock = (block) => {
|
|
|
204
221
|
if (type === "text") return TextPart.make({ text: Option.getOrElse(contentBlockText(block), () => "") });
|
|
205
222
|
if (type === "image") return Option.getOrElse(imagePartFromBlock(block), () => TextPart.make({ text: fallbackTextForContentBlock(block) }));
|
|
206
223
|
if (type === "audio") return Option.getOrElse(audioPartFromBlock(block), () => TextPart.make({ text: fallbackTextForContentBlock(block) }));
|
|
207
|
-
if (type === "resource") return
|
|
224
|
+
if (type === "resource") return Option.getOrElse(embeddedResourcePart(block), () => TextPart.make({ text: fallbackTextForContentBlock(block) }));
|
|
208
225
|
if (type === "resource_link") return TextPart.make({ text: resourceLinkText(block).pipe(Option.getOrElse(() => fallbackTextForContentBlock(block))) });
|
|
209
226
|
return TextPart.make({ text: fallbackTextForContentBlock(block) });
|
|
210
227
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.mjs","names":["Arr"],"sources":["../../src/client/protocol.ts"],"sourcesContent":["import { Array as Arr, Effect, Option, Predicate } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n AudioPart,\n ImagePart,\n TextPart,\n ToolDef,\n ToolJsonSchemaObject,\n ToolResult,\n decodeToolJsonSchemaObject,\n inlineBase64Source\n} from '@yolk-sdk/agent/protocol'\nimport type { Content, ContentPart, ToolExposure } from '@yolk-sdk/agent/protocol'\nimport { McpError } from './errors.ts'\n\nexport const latestMcpProtocolVersion = '2026-07-28'\n\nexport const legacyMcpProtocolVersion = '2024-11-05'\n\nexport const JsonRpcErrorObject = Schema.Struct({\n code: Schema.Number,\n message: Schema.String,\n data: Schema.optional(Schema.Unknown)\n})\n\nexport type JsonRpcErrorObject = typeof JsonRpcErrorObject.Type\n\nexport const JsonRpcSuccessResponse = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number, Schema.Null]),\n result: Schema.Unknown\n})\n\nexport type JsonRpcSuccessResponse = typeof JsonRpcSuccessResponse.Type\n\nexport const JsonRpcErrorResponse = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number, Schema.Null]),\n error: JsonRpcErrorObject\n})\n\nexport type JsonRpcErrorResponse = typeof JsonRpcErrorResponse.Type\n\nexport const JsonRpcResponse = Schema.Union([JsonRpcSuccessResponse, JsonRpcErrorResponse])\n\nexport type JsonRpcResponse = typeof JsonRpcResponse.Type\n\nexport const JsonRpcRequest = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number]),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nexport type JsonRpcRequest = typeof JsonRpcRequest.Type\n\nexport const JsonRpcNotification = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nexport type JsonRpcNotification = typeof JsonRpcNotification.Type\n\nexport const JsonRpcMessage = Schema.Union([JsonRpcRequest, JsonRpcNotification])\n\nexport type JsonRpcMessage = typeof JsonRpcMessage.Type\n\nexport const McpToolAnnotations = Schema.Record(Schema.String, Schema.Unknown)\n\nexport type McpToolAnnotations = typeof McpToolAnnotations.Type\n\nexport const McpTool = Schema.Struct({\n name: Schema.String,\n title: Schema.optional(Schema.String),\n description: Schema.optional(Schema.String),\n inputSchema: Schema.optional(ToolJsonSchemaObject),\n outputSchema: Schema.optional(Schema.Unknown),\n annotations: Schema.optional(McpToolAnnotations)\n})\n\nexport type McpTool = typeof McpTool.Type\n\nexport const ToolsListResult = Schema.Struct({\n tools: Schema.Array(McpTool)\n})\n\nexport type ToolsListResult = typeof ToolsListResult.Type\n\nexport const TextContentBlock = Schema.Struct({\n type: Schema.Literal('text'),\n text: Schema.String\n})\n\nexport type TextContentBlock = typeof TextContentBlock.Type\n\nexport const GenericContentBlock = Schema.Record(Schema.String, Schema.Unknown)\n\nexport type GenericContentBlock = typeof GenericContentBlock.Type\n\nconst EmbeddedResourceContentBlock = Schema.Struct({\n type: Schema.Literal('resource'),\n resource: Schema.Struct({\n uri: Schema.optional(Schema.String),\n text: Schema.optional(Schema.String),\n blob: Schema.optional(Schema.String),\n mimeType: Schema.optional(Schema.String)\n })\n})\n\nconst ResourceLinkContentBlock = Schema.Struct({\n type: Schema.Literal('resource_link'),\n uri: Schema.String,\n name: Schema.optional(Schema.String),\n mimeType: Schema.optional(Schema.String)\n})\n\nexport const ToolCallResult = Schema.Struct({\n content: Schema.optional(Schema.Array(GenericContentBlock)),\n isError: Schema.optional(Schema.Boolean),\n structuredContent: Schema.optional(Schema.Unknown)\n})\n\nexport type ToolCallResult = typeof ToolCallResult.Type\n\nexport const InitializeClientInfo = Schema.Struct({\n name: Schema.String,\n version: Schema.String\n})\n\nexport type InitializeClientInfo = typeof InitializeClientInfo.Type\n\nexport const InitializeParams = Schema.Struct({\n protocolVersion: Schema.String,\n capabilities: Schema.Record(Schema.String, Schema.Unknown),\n clientInfo: InitializeClientInfo\n})\n\nexport type InitializeParams = typeof InitializeParams.Type\n\nexport const InitializedNotification = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n method: Schema.Literal('notifications/initialized')\n})\n\nexport type InitializedNotification = typeof InitializedNotification.Type\n\nexport const ToolsCallParams = Schema.Struct({\n name: Schema.String,\n arguments: Schema.optional(Schema.Unknown)\n})\n\nexport type ToolsCallParams = typeof ToolsCallParams.Type\n\nexport const makeJsonRpcRequest = (input: {\n readonly id: string | number\n readonly method: string\n readonly params?: unknown\n}): JsonRpcRequest => {\n const id = input.id\n const method = input.method\n\n if (input.params !== undefined) {\n return JsonRpcRequest.make({\n jsonrpc: '2.0',\n id,\n method,\n params: input.params\n })\n }\n\n return JsonRpcRequest.make({\n jsonrpc: '2.0',\n id,\n method\n })\n}\n\nexport const makeInitializedNotification = (): JsonRpcNotification =>\n InitializedNotification.make({\n jsonrpc: '2.0',\n method: 'notifications/initialized'\n })\n\nexport const makeInitializeParams = (input: {\n readonly name: string\n readonly version: string\n}): InitializeParams =>\n InitializeParams.make({\n protocolVersion: legacyMcpProtocolVersion,\n capabilities: {},\n clientInfo: InitializeClientInfo.make({\n name: input.name,\n version: input.version\n })\n })\n\nexport const jsonRpcErrorToMcpError = (server: string, error: JsonRpcErrorObject) =>\n new McpError({\n server,\n message: `MCP JSON-RPC error ${error.code}: ${error.message}`,\n cause: 'protocol'\n })\n\n/** Tool exposure (`callableBy`/`discovery`/`loading`) for adapted MCP tools: one value for every\n * tool, or per listed tool.\n * Omitted: the agent defaults (`callableBy: 'all'`). `resolveTools` still rejects invalid\n * combinations (for example `discovery` without `callableBy: 'codemode'`).\n */\nexport type McpToolExposureResolver =\n | ToolExposure\n | ((tool: McpTool, serverName: string) => ToolExposure)\n\ntype McpToolDefFields = {\n name: string\n description: string\n parameters: ToolDef['parameters']\n outputSchema?: ToolDef['outputSchema']\n callableBy?: ToolDef['callableBy']\n discovery?: ToolDef['discovery']\n loading?: ToolDef['loading']\n}\n\n/** Adapts one listed MCP tool. A present `outputSchema` that is a plain JSON Schema object\n * passes through as declaration-only `ToolDef.outputSchema`; any other value is omitted.\n * `exposure` (host policy) sets `callableBy`/`discovery`/`loading`; without it none is set.\n */\nexport const mcpToolToToolDef = (input: {\n readonly serverName: string\n readonly tool: McpTool\n readonly exposure?: McpToolExposureResolver\n}) => {\n const fields: McpToolDefFields = {\n name: `${sanitizeMcpName(input.serverName)}_${sanitizeMcpName(input.tool.name)}`,\n description: input.tool.description ?? `MCP tool ${input.serverName}/${input.tool.name}`,\n parameters: input.tool.inputSchema ?? { type: 'object', additionalProperties: true }\n }\n\n const outputSchema = decodeToolJsonSchemaObject(input.tool.outputSchema)\n\n if (Option.isSome(outputSchema)) fields.outputSchema = outputSchema.value\n\n const exposure = Predicate.isFunction(input.exposure)\n ? input.exposure(input.tool, input.serverName)\n : input.exposure\n\n if (exposure?.callableBy !== undefined) fields.callableBy = exposure.callableBy\n\n if (exposure?.discovery !== undefined) fields.discovery = exposure.discovery\n\n if (exposure?.loading !== undefined) fields.loading = exposure.loading\n\n return ToolDef.make(fields)\n}\n\nexport const sanitizeMcpName = (name: string) => {\n const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, '_')\n\n return sanitized.length === 0 ? 'mcp' : sanitized\n}\n\nconst stringProperty = (block: GenericContentBlock, key: string) =>\n Schema.decodeUnknownOption(Schema.String)(block[key])\n\nconst contentBlockText = (block: GenericContentBlock): Option.Option<string> => {\n const type = block['type']\n const text = stringProperty(block, 'text')\n\n if (type === 'text') {\n return text\n }\n\n return Option.none()\n}\n\nconst fallbackTextForContentBlock = (block: GenericContentBlock) => {\n const type = stringProperty(block, 'type').pipe(Option.getOrElse(() => 'unknown'))\n const name = stringProperty(block, 'name')\n const uri = stringProperty(block, 'uri')\n const url = stringProperty(block, 'url')\n const label = Option.getOrElse(Option.firstSomeOf([name, uri, url]), () => type)\n\n switch (type) {\n case 'resource':\n return `MCP resource: ${label}`\n case 'resource_link':\n return `MCP resource link: ${label}`\n case 'image':\n return `MCP image: ${label}`\n case 'audio':\n return `MCP audio: ${label}`\n default:\n return `Unsupported MCP ${type} content.`\n }\n}\n\nconst embeddedResourceText = (block: GenericContentBlock): Option.Option<string> =>\n Schema.decodeUnknownOption(EmbeddedResourceContentBlock)(block).pipe(\n Option.flatMap(({ resource }) => {\n if (resource.text !== undefined) {\n return Option.some(resource.text)\n }\n\n return Option.all({\n uri: Option.fromNullishOr(resource.uri),\n blob: Option.fromNullishOr(resource.blob)\n }).pipe(Option.map(({ uri, blob }) => `MCP resource: ${uri}\\n${blob}`))\n })\n )\n\nconst resourceLinkText = (block: GenericContentBlock): Option.Option<string> =>\n Schema.decodeUnknownOption(ResourceLinkContentBlock)(block).pipe(\n Option.map(({ name, uri }) => {\n const label = name ?? uri\n\n return `MCP resource link: ${label} (${uri})`\n })\n )\n\nconst imagePartFromBlock = (block: GenericContentBlock): Option.Option<ContentPart> =>\n Option.all({\n data: stringProperty(block, 'data'),\n mimeType: stringProperty(block, 'mimeType')\n }).pipe(\n Option.map(({ data, mimeType }) =>\n ImagePart.make({ source: inlineBase64Source(data), mimeType })\n )\n )\n\nconst audioPartFromBlock = (block: GenericContentBlock): Option.Option<ContentPart> =>\n Option.all({\n data: stringProperty(block, 'data'),\n mimeType: stringProperty(block, 'mimeType')\n }).pipe(\n Option.map(({ data, mimeType }) =>\n AudioPart.make({ source: inlineBase64Source(data), mimeType })\n )\n )\n\nconst contentPartFromBlock = (block: GenericContentBlock): ContentPart => {\n const type = block['type']\n\n if (type === 'text') {\n return TextPart.make({ text: Option.getOrElse(contentBlockText(block), () => '') })\n }\n\n if (type === 'image') {\n return Option.getOrElse(imagePartFromBlock(block), () =>\n TextPart.make({ text: fallbackTextForContentBlock(block) })\n )\n }\n\n if (type === 'audio') {\n return Option.getOrElse(audioPartFromBlock(block), () =>\n TextPart.make({ text: fallbackTextForContentBlock(block) })\n )\n }\n\n if (type === 'resource') {\n return TextPart.make({\n text: embeddedResourceText(block).pipe(\n Option.getOrElse(() => fallbackTextForContentBlock(block))\n )\n })\n }\n\n if (type === 'resource_link') {\n return TextPart.make({\n text: resourceLinkText(block).pipe(Option.getOrElse(() => fallbackTextForContentBlock(block)))\n })\n }\n\n return TextPart.make({ text: fallbackTextForContentBlock(block) })\n}\n\nconst contentFromBlocks = (blocks: ReadonlyArray<GenericContentBlock>): Content => {\n const textBlocks = Arr.getSomes(Arr.map(blocks, contentBlockText))\n\n if (textBlocks.length === blocks.length) {\n return textBlocks.join('\\n')\n }\n\n return Arr.map(blocks, contentPartFromBlock)\n}\n\nexport const toolCallResultToToolResult = (input: {\n readonly toolCallId: string\n readonly result: ToolCallResult\n}) => {\n const content = input.result.content ?? []\n\n const resultContent =\n content.length > 0\n ? contentFromBlocks(content)\n : input.result.structuredContent === undefined\n ? 'Unsupported MCP tool content.'\n : 'Structured MCP tool result.'\n\n return ToolResult.make({\n toolCallId: input.toolCallId,\n content: resultContent,\n isError: input.result.isError,\n structuredContent: input.result.structuredContent\n })\n}\n\nexport const decodeJsonRpcResponse = Schema.decodeUnknownEffect(JsonRpcResponse)\n\nexport const decodeToolsListResult = Schema.decodeUnknownEffect(ToolsListResult)\n\nexport const decodeToolCallResult = Schema.decodeUnknownEffect(ToolCallResult)\n\nexport const encodeJsonRpcMessage = (\n server: string,\n message: JsonRpcRequest | JsonRpcNotification\n) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(message).pipe(\n Effect.mapError(\n error =>\n new McpError({\n server,\n message: `Could not encode MCP JSON-RPC message: ${String(error)}`,\n cause: 'encoding'\n })\n )\n )\n\nconst decodeJsonString = (server: string, text: string) =>\n Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(text).pipe(\n Effect.mapError(\n error =>\n new McpError({\n server,\n message: `Malformed MCP JSON: ${String(error)}`,\n cause: 'parse'\n })\n )\n )\n\nexport const decodeJsonRpcResponseFromJson = (server: string, text: string) =>\n decodeJsonString(server, text).pipe(\n Effect.flatMap(decodeJsonRpcResponse),\n Effect.mapError(error =>\n error instanceof McpError\n ? error\n : new McpError({\n server,\n message: `Invalid MCP JSON-RPC response: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n\nexport const decodeJsonRpcMessageFromJson = (server: string, text: string) =>\n decodeJsonString(server, text).pipe(\n Effect.flatMap(Schema.decodeUnknownEffect(JsonRpcMessage)),\n Effect.mapError(error =>\n error instanceof McpError\n ? error\n : new McpError({\n server,\n message: `Invalid MCP JSON-RPC message: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"protocol.mjs","names":["Arr"],"sources":["../../src/client/protocol.ts"],"sourcesContent":["import { Array as Arr, Effect, Option, Predicate } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n AudioPart,\n FilePart,\n ImagePart,\n TextPart,\n ToolDef,\n ToolJsonSchemaObject,\n ToolResult,\n decodeToolJsonSchemaObject,\n inlineBase64Source\n} from '@yolk-sdk/agent/protocol'\nimport type { Content, ContentPart, ToolExposure } from '@yolk-sdk/agent/protocol'\nimport { McpError } from './errors.ts'\n\nexport const latestMcpProtocolVersion = '2026-07-28'\n\nexport const legacyMcpProtocolVersion = '2024-11-05'\n\nexport const JsonRpcErrorObject = Schema.Struct({\n code: Schema.Number,\n message: Schema.String,\n data: Schema.optional(Schema.Unknown)\n})\n\nexport type JsonRpcErrorObject = typeof JsonRpcErrorObject.Type\n\nexport const JsonRpcSuccessResponse = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number, Schema.Null]),\n result: Schema.Unknown\n})\n\nexport type JsonRpcSuccessResponse = typeof JsonRpcSuccessResponse.Type\n\nexport const JsonRpcErrorResponse = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number, Schema.Null]),\n error: JsonRpcErrorObject\n})\n\nexport type JsonRpcErrorResponse = typeof JsonRpcErrorResponse.Type\n\nexport const JsonRpcResponse = Schema.Union([JsonRpcSuccessResponse, JsonRpcErrorResponse])\n\nexport type JsonRpcResponse = typeof JsonRpcResponse.Type\n\nexport const JsonRpcRequest = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number]),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nexport type JsonRpcRequest = typeof JsonRpcRequest.Type\n\nexport const JsonRpcNotification = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nexport type JsonRpcNotification = typeof JsonRpcNotification.Type\n\nexport const JsonRpcMessage = Schema.Union([JsonRpcRequest, JsonRpcNotification])\n\nexport type JsonRpcMessage = typeof JsonRpcMessage.Type\n\nexport const McpToolAnnotations = Schema.Record(Schema.String, Schema.Unknown)\n\nexport type McpToolAnnotations = typeof McpToolAnnotations.Type\n\nexport const McpTool = Schema.Struct({\n name: Schema.String,\n title: Schema.optional(Schema.String),\n description: Schema.optional(Schema.String),\n inputSchema: Schema.optional(ToolJsonSchemaObject),\n outputSchema: Schema.optional(Schema.Unknown),\n annotations: Schema.optional(McpToolAnnotations)\n})\n\nexport type McpTool = typeof McpTool.Type\n\nexport const ToolsListResult = Schema.Struct({\n tools: Schema.Array(McpTool)\n})\n\nexport type ToolsListResult = typeof ToolsListResult.Type\n\nexport const TextContentBlock = Schema.Struct({\n type: Schema.Literal('text'),\n text: Schema.String\n})\n\nexport type TextContentBlock = typeof TextContentBlock.Type\n\nexport const GenericContentBlock = Schema.Record(Schema.String, Schema.Unknown)\n\nexport type GenericContentBlock = typeof GenericContentBlock.Type\n\nconst EmbeddedResourceContentBlock = Schema.Struct({\n type: Schema.Literal('resource'),\n resource: Schema.Struct({\n uri: Schema.optional(Schema.String),\n text: Schema.optional(Schema.String),\n blob: Schema.optional(Schema.String),\n mimeType: Schema.optional(Schema.String)\n })\n})\n\nconst ResourceLinkContentBlock = Schema.Struct({\n type: Schema.Literal('resource_link'),\n uri: Schema.String,\n name: Schema.optional(Schema.String),\n mimeType: Schema.optional(Schema.String)\n})\n\nexport const ToolCallResult = Schema.Struct({\n content: Schema.optional(Schema.Array(GenericContentBlock)),\n isError: Schema.optional(Schema.Boolean),\n structuredContent: Schema.optional(Schema.Unknown)\n})\n\nexport type ToolCallResult = typeof ToolCallResult.Type\n\nexport const InitializeClientInfo = Schema.Struct({\n name: Schema.String,\n version: Schema.String\n})\n\nexport type InitializeClientInfo = typeof InitializeClientInfo.Type\n\nexport const InitializeParams = Schema.Struct({\n protocolVersion: Schema.String,\n capabilities: Schema.Record(Schema.String, Schema.Unknown),\n clientInfo: InitializeClientInfo\n})\n\nexport type InitializeParams = typeof InitializeParams.Type\n\nexport const InitializedNotification = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n method: Schema.Literal('notifications/initialized')\n})\n\nexport type InitializedNotification = typeof InitializedNotification.Type\n\nexport const ToolsCallParams = Schema.Struct({\n name: Schema.String,\n arguments: Schema.optional(Schema.Unknown)\n})\n\nexport type ToolsCallParams = typeof ToolsCallParams.Type\n\nexport const makeJsonRpcRequest = (input: {\n readonly id: string | number\n readonly method: string\n readonly params?: unknown\n}): JsonRpcRequest => {\n const id = input.id\n const method = input.method\n\n if (input.params !== undefined) {\n return JsonRpcRequest.make({\n jsonrpc: '2.0',\n id,\n method,\n params: input.params\n })\n }\n\n return JsonRpcRequest.make({\n jsonrpc: '2.0',\n id,\n method\n })\n}\n\nexport const makeInitializedNotification = (): JsonRpcNotification =>\n InitializedNotification.make({\n jsonrpc: '2.0',\n method: 'notifications/initialized'\n })\n\nexport const makeInitializeParams = (input: {\n readonly name: string\n readonly version: string\n}): InitializeParams =>\n InitializeParams.make({\n protocolVersion: legacyMcpProtocolVersion,\n capabilities: {},\n clientInfo: InitializeClientInfo.make({\n name: input.name,\n version: input.version\n })\n })\n\nexport const jsonRpcErrorToMcpError = (server: string, error: JsonRpcErrorObject) =>\n new McpError({\n server,\n message: `MCP JSON-RPC error ${error.code}: ${error.message}`,\n cause: 'protocol'\n })\n\n/** Tool exposure (`callableBy`/`discovery`/`loading`) for adapted MCP tools: one value for every\n * tool, or per listed tool.\n * Omitted: the agent defaults (`callableBy: 'all'`). `resolveTools` still rejects invalid\n * combinations (for example `discovery` without `callableBy: 'codemode'`).\n */\nexport type McpToolExposureResolver =\n | ToolExposure\n | ((tool: McpTool, serverName: string) => ToolExposure)\n\ntype McpToolDefFields = {\n name: string\n description: string\n parameters: ToolDef['parameters']\n outputSchema?: ToolDef['outputSchema']\n callableBy?: ToolDef['callableBy']\n discovery?: ToolDef['discovery']\n loading?: ToolDef['loading']\n}\n\n/** Adapts one listed MCP tool. A present `outputSchema` that is a plain JSON Schema object\n * passes through as declaration-only `ToolDef.outputSchema`; any other value is omitted.\n * `exposure` (host policy) sets `callableBy`/`discovery`/`loading`; without it none is set.\n */\nexport const mcpToolToToolDef = (input: {\n readonly serverName: string\n readonly tool: McpTool\n readonly exposure?: McpToolExposureResolver\n}) => {\n const fields: McpToolDefFields = {\n name: `${sanitizeMcpName(input.serverName)}_${sanitizeMcpName(input.tool.name)}`,\n description: input.tool.description ?? `MCP tool ${input.serverName}/${input.tool.name}`,\n parameters: input.tool.inputSchema ?? { type: 'object', additionalProperties: true }\n }\n\n const outputSchema = decodeToolJsonSchemaObject(input.tool.outputSchema)\n\n if (Option.isSome(outputSchema)) fields.outputSchema = outputSchema.value\n\n const exposure = Predicate.isFunction(input.exposure)\n ? input.exposure(input.tool, input.serverName)\n : input.exposure\n\n if (exposure?.callableBy !== undefined) fields.callableBy = exposure.callableBy\n\n if (exposure?.discovery !== undefined) fields.discovery = exposure.discovery\n\n if (exposure?.loading !== undefined) fields.loading = exposure.loading\n\n return ToolDef.make(fields)\n}\n\nexport const sanitizeMcpName = (name: string) => {\n const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, '_')\n\n return sanitized.length === 0 ? 'mcp' : sanitized\n}\n\nconst stringProperty = (block: GenericContentBlock, key: string) =>\n Schema.decodeUnknownOption(Schema.String)(block[key])\n\nconst contentBlockText = (block: GenericContentBlock): Option.Option<string> => {\n const type = block['type']\n const text = stringProperty(block, 'text')\n\n if (type === 'text') {\n return text\n }\n\n return Option.none()\n}\n\nconst fallbackTextForContentBlock = (block: GenericContentBlock) => {\n const type = stringProperty(block, 'type').pipe(Option.getOrElse(() => 'unknown'))\n const name = stringProperty(block, 'name')\n const uri = stringProperty(block, 'uri')\n const url = stringProperty(block, 'url')\n const label = Option.getOrElse(Option.firstSomeOf([name, uri, url]), () => type)\n\n switch (type) {\n case 'resource':\n return `MCP resource: ${label}`\n case 'resource_link':\n return `MCP resource link: ${label}`\n case 'image':\n return `MCP image: ${label}`\n case 'audio':\n return `MCP audio: ${label}`\n default:\n return `Unsupported MCP ${type} content.`\n }\n}\n\nconst resourceFilename = (uri: string) => {\n const segments = (uri.split(/[?#]/u, 1)[0] ?? '').split('/').filter(part => part.length > 0)\n const segment = segments[segments.length - 1]\n\n if (segment === undefined || segment.endsWith(':')) return undefined\n\n try {\n return decodeURIComponent(segment)\n } catch {\n return segment\n }\n}\n\n// Embedded text stays text; a blob becomes a file part that tool resolution captures (ADR 0009),\n// so its base64 never reaches the model.\nconst embeddedResourcePart = (block: GenericContentBlock): Option.Option<ContentPart> =>\n Schema.decodeUnknownOption(EmbeddedResourceContentBlock)(block).pipe(\n Option.flatMap(({ resource }): Option.Option<ContentPart> => {\n if (resource.text !== undefined) return Option.some(TextPart.make({ text: resource.text }))\n\n if (resource.blob === undefined) return Option.none()\n\n const mimeType = resource.mimeType ?? 'application/octet-stream'\n const filename = resource.uri === undefined ? undefined : resourceFilename(resource.uri)\n\n return Option.some(\n filename === undefined\n ? FilePart.make({ source: inlineBase64Source(resource.blob), mimeType })\n : FilePart.make({ source: inlineBase64Source(resource.blob), mimeType, filename })\n )\n })\n )\n\nconst resourceLinkText = (block: GenericContentBlock): Option.Option<string> =>\n Schema.decodeUnknownOption(ResourceLinkContentBlock)(block).pipe(\n Option.map(({ name, uri }) => {\n const label = name ?? uri\n\n return `MCP resource link: ${label} (${uri})`\n })\n )\n\nconst imagePartFromBlock = (block: GenericContentBlock): Option.Option<ContentPart> =>\n Option.all({\n data: stringProperty(block, 'data'),\n mimeType: stringProperty(block, 'mimeType')\n }).pipe(\n Option.map(({ data, mimeType }) =>\n ImagePart.make({ source: inlineBase64Source(data), mimeType })\n )\n )\n\nconst audioPartFromBlock = (block: GenericContentBlock): Option.Option<ContentPart> =>\n Option.all({\n data: stringProperty(block, 'data'),\n mimeType: stringProperty(block, 'mimeType')\n }).pipe(\n Option.map(({ data, mimeType }) =>\n AudioPart.make({ source: inlineBase64Source(data), mimeType })\n )\n )\n\nconst contentPartFromBlock = (block: GenericContentBlock): ContentPart => {\n const type = block['type']\n\n if (type === 'text') {\n return TextPart.make({ text: Option.getOrElse(contentBlockText(block), () => '') })\n }\n\n if (type === 'image') {\n return Option.getOrElse(imagePartFromBlock(block), () =>\n TextPart.make({ text: fallbackTextForContentBlock(block) })\n )\n }\n\n if (type === 'audio') {\n return Option.getOrElse(audioPartFromBlock(block), () =>\n TextPart.make({ text: fallbackTextForContentBlock(block) })\n )\n }\n\n if (type === 'resource') {\n return Option.getOrElse(embeddedResourcePart(block), () =>\n TextPart.make({ text: fallbackTextForContentBlock(block) })\n )\n }\n\n if (type === 'resource_link') {\n return TextPart.make({\n text: resourceLinkText(block).pipe(Option.getOrElse(() => fallbackTextForContentBlock(block)))\n })\n }\n\n return TextPart.make({ text: fallbackTextForContentBlock(block) })\n}\n\nconst contentFromBlocks = (blocks: ReadonlyArray<GenericContentBlock>): Content => {\n const textBlocks = Arr.getSomes(Arr.map(blocks, contentBlockText))\n\n if (textBlocks.length === blocks.length) {\n return textBlocks.join('\\n')\n }\n\n return Arr.map(blocks, contentPartFromBlock)\n}\n\nexport const toolCallResultToToolResult = (input: {\n readonly toolCallId: string\n readonly result: ToolCallResult\n}) => {\n const content = input.result.content ?? []\n\n const resultContent =\n content.length > 0\n ? contentFromBlocks(content)\n : input.result.structuredContent === undefined\n ? 'Unsupported MCP tool content.'\n : 'Structured MCP tool result.'\n\n return ToolResult.make({\n toolCallId: input.toolCallId,\n content: resultContent,\n isError: input.result.isError,\n structuredContent: input.result.structuredContent\n })\n}\n\nexport const decodeJsonRpcResponse = Schema.decodeUnknownEffect(JsonRpcResponse)\n\nexport const decodeToolsListResult = Schema.decodeUnknownEffect(ToolsListResult)\n\nexport const decodeToolCallResult = Schema.decodeUnknownEffect(ToolCallResult)\n\nexport const encodeJsonRpcMessage = (\n server: string,\n message: JsonRpcRequest | JsonRpcNotification\n) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(message).pipe(\n Effect.mapError(\n error =>\n new McpError({\n server,\n message: `Could not encode MCP JSON-RPC message: ${String(error)}`,\n cause: 'encoding'\n })\n )\n )\n\nconst decodeJsonString = (server: string, text: string) =>\n Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(text).pipe(\n Effect.mapError(\n error =>\n new McpError({\n server,\n message: `Malformed MCP JSON: ${String(error)}`,\n cause: 'parse'\n })\n )\n )\n\nexport const decodeJsonRpcResponseFromJson = (server: string, text: string) =>\n decodeJsonString(server, text).pipe(\n Effect.flatMap(decodeJsonRpcResponse),\n Effect.mapError(error =>\n error instanceof McpError\n ? error\n : new McpError({\n server,\n message: `Invalid MCP JSON-RPC response: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n\nexport const decodeJsonRpcMessageFromJson = (server: string, text: string) =>\n decodeJsonString(server, text).pipe(\n Effect.flatMap(Schema.decodeUnknownEffect(JsonRpcMessage)),\n Effect.mapError(error =>\n error instanceof McpError\n ? error\n : new McpError({\n server,\n message: `Invalid MCP JSON-RPC message: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.mts","names":[],"sources":["../../src/server/server.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"server.d.mts","names":[],"sources":["../../src/server/server.ts"],"mappings":";;;;;KAiQY,aAAA;EAAA,SACD,GAAA,EAAK,OAAA;EAAA,SACL,OAAA,GAAU,IAAA,EAAM,QAAA,KAAa,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,cAAA,EAAgB,CAAA;AAAA;AAAA,KAGtE,aAAA;EAAA,SACD,UAAA,GAAa,IAAA,aAAiB,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,MAAA,UAAgB,cAAA,EAAgB,CAAA;EAAA,SACnF,UAAA,GAAa,IAAA,aAAiB,MAAA,CAAO,MAAA,SAAe,cAAA,EAAgB,CAAA;EAAA,SACpE,iBAAA,GAAoB,OAAA,EAAS,OAAA,KAAY,MAAA,CAAO,MAAA,CAAO,QAAA,SAAiB,CAAA;AAAA;AAAA,cA0BtE,iBAAA,MAAwB,KAAA;EAAA,SAC1B,IAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA,EAAO,aAAA,CAAc,aAAA,CAAc,CAAA;EAAA,SACnC,sBAAA,GAAyB,aAAA;AAAA,MAChC,aAAA,CAAc,CAAA"}
|
package/dist/server/server.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpServerError } from "./errors.mjs";
|
|
2
2
|
import { Array as Array$1, Effect, Match, Option, Predicate, Result } from "effect";
|
|
3
3
|
import * as Schema from "effect/Schema";
|
|
4
|
-
import { ToolCall, ToolResult, attachmentSourceBase64, attachmentSourcePreview, contentParts } from "@yolk-sdk/agent/protocol";
|
|
4
|
+
import { ToolCall, ToolResult, attachmentSourceBase64, attachmentSourcePreview, contentParts, filePartText } from "@yolk-sdk/agent/protocol";
|
|
5
5
|
import { McpServer, createMcpHandler, fromJsonSchema, originValidationResponse } from "@modelcontextprotocol/server";
|
|
6
6
|
import { legacyMcpProtocolVersion } from "@yolk-sdk/mcp/client";
|
|
7
7
|
//#region src/server/server.ts
|
|
@@ -108,6 +108,19 @@ const mcpContentBlockFromPart = (part) => Match.value(part).pipe(Match.withRetur
|
|
|
108
108
|
data,
|
|
109
109
|
mimeType: current.mimeType
|
|
110
110
|
})
|
|
111
|
+
})), Match.tag("File", (current) => Option.match(attachmentSourceBase64(current.source), {
|
|
112
|
+
onNone: () => ({
|
|
113
|
+
type: "text",
|
|
114
|
+
text: filePartText(current)
|
|
115
|
+
}),
|
|
116
|
+
onSome: (data) => ({
|
|
117
|
+
type: "resource",
|
|
118
|
+
resource: {
|
|
119
|
+
uri: documentResourceUri(current.filename ?? "file"),
|
|
120
|
+
mimeType: current.mimeType,
|
|
121
|
+
blob: data
|
|
122
|
+
}
|
|
123
|
+
})
|
|
111
124
|
})), Match.exhaustive);
|
|
112
125
|
const mcpResultFromToolResult = (result) => {
|
|
113
126
|
const content = Array$1.map(contentParts(result.content), mcpContentBlockFromPart);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.mjs","names":["Arr","SdkMcpServer"],"sources":["../../src/server/server.ts"],"sourcesContent":["import { Array as Arr, Effect, Match, Option, Predicate, Result } from 'effect'\nimport type { Context } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n McpServer as SdkMcpServer,\n createMcpHandler,\n fromJsonSchema,\n originValidationResponse,\n type CallToolResult as SdkCallToolResult,\n type ContentBlock as SdkContentBlock\n} from '@modelcontextprotocol/server'\nimport {\n ToolCall,\n ToolResult,\n attachmentSourceBase64,\n attachmentSourcePreview,\n contentParts,\n type ContentPart,\n type ToolDef\n} from '@yolk-sdk/agent/protocol'\nimport { legacyMcpProtocolVersion } from '@yolk-sdk/mcp/client'\nimport { McpServerError } from './errors.ts'\n\ntype JsonRpcRequest = {\n readonly jsonrpc: '2.0'\n readonly id: string | number\n readonly method: string\n readonly params?: unknown\n}\n\ntype JsonRpcNotification = {\n readonly jsonrpc: '2.0'\n readonly method: string\n readonly params?: unknown\n}\n\ntype JsonRpcResponse = {\n readonly jsonrpc: '2.0'\n readonly id: string | number | null\n readonly result?: unknown\n readonly error?: {\n readonly code: number\n readonly message: string\n }\n}\n\nconst JsonRpcRequestSchema = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number]),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nconst JsonRpcNotificationSchema = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nconst CallToolParamsSchema = Schema.Struct({\n name: Schema.String,\n arguments: Schema.optional(Schema.Unknown)\n})\n\nconst JsonRpcMessageSchema = Schema.Union([JsonRpcRequestSchema, JsonRpcNotificationSchema])\n\ntype JsonRpcMessage = typeof JsonRpcMessageSchema.Type\n\nconst DecodedMessageLine = Schema.TaggedStruct('Message', {\n message: Schema.Unknown\n})\n\nconst DecodedResponseLine = Schema.TaggedStruct('Response', {\n response: Schema.Unknown\n})\n\ntype DecodedLine =\n | {\n readonly _tag: 'Message'\n readonly message: JsonRpcMessage\n }\n | {\n readonly _tag: 'Response'\n readonly response: Option.Option<string>\n }\n\nconst decodedMessage = (message: JsonRpcMessage): DecodedLine => ({\n ...DecodedMessageLine.make({ message }),\n message\n})\n\nconst decodedResponse = (response: Option.Option<string>): DecodedLine => ({\n ...DecodedResponseLine.make({ response }),\n response\n})\n\nconst decodeJson = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))\n\nconst decodeJsonRpcMessage = Schema.decodeUnknownEffect(JsonRpcMessageSchema)\n\nconst decodeCallToolParams = Schema.decodeUnknownEffect(CallToolParamsSchema)\n\nconst encodeJson = (value: JsonRpcResponse) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(value).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Could not encode MCP response: ${String(error)}`,\n cause: 'encoding'\n })\n )\n )\n\nconst decodeMessage = (line: string) =>\n decodeJson(line).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Malformed MCP JSON: ${String(error)}`,\n cause: 'parse'\n })\n ),\n Effect.flatMap(value =>\n decodeJsonRpcMessage(value).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Invalid MCP JSON-RPC message: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n )\n )\n\nconst successResponse = (id: string | number, result: unknown): JsonRpcResponse => ({\n jsonrpc: '2.0',\n id,\n result\n})\n\nconst errorResponse = (\n id: string | number | null,\n code: number,\n message: string\n): JsonRpcResponse => ({\n jsonrpc: '2.0',\n id,\n error: { code, message }\n})\n\nconst unknownToMessage = (error: unknown) =>\n error instanceof Error ? error.message : String(error)\n\nconst isRequest = (message: JsonRpcRequest | JsonRpcNotification): message is JsonRpcRequest =>\n 'id' in message\n\nconst protocolErrorCode = (error: McpServerError) => {\n switch (error.cause) {\n case 'parse':\n return -32_700\n case 'validation':\n return -32_600\n case 'protocol':\n return -32_603\n case 'tool_error':\n case 'encoding':\n return -32_000\n }\n}\n\nconst protocolErrorResponse = (id: string | number | null, error: McpServerError) =>\n errorResponse(id, protocolErrorCode(error), error.message)\n\nconst documentResourceUri = (filename: string) => `file:///${encodeURIComponent(filename)}`\n\nconst mcpContentBlockFromPart = (part: ContentPart): SdkContentBlock =>\n Match.value(part).pipe(\n Match.withReturnType<SdkContentBlock>(),\n Match.tag('Text', current => ({ type: 'text', text: current.text })),\n Match.tag('Image', current =>\n Option.match(attachmentSourceBase64(current.source), {\n onNone: () => ({\n type: 'text',\n text: `Image attachment: ${attachmentSourcePreview(current.source)}`\n }),\n onSome: data => ({ type: 'image', data, mimeType: current.mimeType })\n })\n ),\n Match.tag('Document', current =>\n Option.match(attachmentSourceBase64(current.source), {\n onNone: () => ({\n type: 'text',\n text: `Document attachment: ${attachmentSourcePreview(current.source)}`\n }),\n onSome: data => ({\n type: 'resource',\n resource: {\n uri: documentResourceUri(current.filename),\n name: current.title ?? current.filename,\n mimeType: current.mimeType,\n blob: data\n }\n })\n })\n ),\n Match.tag('Audio', current =>\n Option.match(attachmentSourceBase64(current.source), {\n onNone: () => ({\n type: 'text',\n text: `Audio attachment: ${attachmentSourcePreview(current.source)}`\n }),\n onSome: data => ({ type: 'audio', data, mimeType: current.mimeType })\n })\n ),\n Match.exhaustive\n )\n\nconst mcpResultFromToolResult = (result: ToolResult): SdkCallToolResult => {\n const content = Arr.map(contentParts(result.content), mcpContentBlockFromPart)\n const base = result.isError === undefined ? { content } : { content, isError: result.isError }\n\n return result.structuredContent === undefined\n ? base\n : { ...base, structuredContent: result.structuredContent }\n}\n\nconst mcpErrorResult = (message: string): SdkCallToolResult => ({\n content: [{ type: 'text', text: message }],\n isError: true\n})\n\nconst mcpResultFromExecutionResult = (\n result: ToolResult | ReturnType<typeof mcpErrorResult>\n): SdkCallToolResult => (result instanceof ToolResult ? mcpResultFromToolResult(result) : result)\n\nconst toolListItem = (tool: ToolDef) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters\n})\n\nexport type McpServerTool<R = never> = {\n readonly def: ToolDef\n readonly execute: (call: ToolCall) => Effect.Effect<ToolResult, McpServerError, R>\n}\n\nexport type McpToolServer<R = never> = {\n readonly handleLine: (line: string) => Effect.Effect<Option.Option<string>, McpServerError, R>\n readonly handleJson: (body: string) => Effect.Effect<string, McpServerError, R>\n readonly handleHttpRequest: (request: Request) => Effect.Effect<Response, never, R>\n}\n\nconst jsonResponse = (body: string, init?: ResponseInit) =>\n new Response(body, {\n ...init,\n headers: {\n 'content-type': 'application/json',\n ...(init?.headers ?? {})\n }\n })\n\nconst methodNotAllowedBody = () =>\n encodeJson(errorResponse(null, -32_600, 'Method not allowed')).pipe(\n Effect.orElseSucceed(\n () => '{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32600,\"message\":\"Method not allowed\"}}'\n )\n )\n\nconst badRequestBody = (message: string) =>\n encodeJson(errorResponse(null, -32_600, message)).pipe(\n Effect.orElseSucceed(\n () => '{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32600,\"message\":\"Bad request\"}}'\n )\n )\n\nexport const makeMcpToolServer = <R>(input: {\n readonly name: string\n readonly version: string\n readonly tools: ReadonlyArray<McpServerTool<R>>\n readonly allowedOriginHostnames?: ReadonlyArray<string>\n}): McpToolServer<R> => {\n const findTool = (name: string) => Arr.findFirst(input.tools, tool => tool.def.name === name)\n\n const toolInputSchemas = input.tools.map(tool => ({\n tool,\n schema: Schema.decodeUnknownOption(Schema.Record(Schema.String, Schema.Unknown))(\n tool.def.parameters\n ).pipe(Option.getOrElse(() => ({ type: 'object', additionalProperties: true })))\n }))\n\n const makeSdkServer = (context: Context.Context<R>) => {\n const server = new SdkMcpServer(\n { name: input.name, version: input.version },\n {\n cacheHints: {\n 'server/discover': { ttlMs: 0, cacheScope: 'private' },\n 'tools/list': { ttlMs: 0, cacheScope: 'private' }\n }\n }\n )\n\n for (const { schema, tool } of toolInputSchemas) {\n server.registerTool(\n tool.def.name,\n {\n description: tool.def.description,\n inputSchema: fromJsonSchema(schema)\n },\n async (args, sdkContext) => {\n const result = await Effect.runPromiseWith(context)(\n tool\n .execute(\n ToolCall.make({\n id: String(sdkContext.mcpReq.id),\n name: tool.def.name,\n params: args\n })\n )\n .pipe(\n Effect.catch(error =>\n Effect.succeed(mcpErrorResult(`MCP tool failed: ${error.message}`))\n )\n )\n )\n\n return mcpResultFromExecutionResult(result)\n }\n )\n }\n\n return server\n }\n\n const handleRequest = (request: JsonRpcRequest) =>\n Effect.gen(function* () {\n switch (request.method) {\n case 'initialize':\n return successResponse(request.id, {\n protocolVersion: legacyMcpProtocolVersion,\n capabilities: { tools: {} },\n serverInfo: { name: input.name, version: input.version }\n })\n case 'tools/list':\n return successResponse(request.id, {\n tools: input.tools.map(tool => toolListItem(tool.def))\n })\n case 'tools/call': {\n const params = yield* decodeCallToolParams(request.params).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Invalid tools/call params: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n\n const tool = findTool(params.name)\n\n if (Option.isNone(tool)) {\n return errorResponse(request.id, -32_602, `Unknown tool: ${params.name}`)\n }\n\n const result = yield* tool.value\n .execute(\n ToolCall.make({\n id: String(request.id),\n name: params.name,\n params: params.arguments ?? {}\n })\n )\n .pipe(\n Effect.catch(error =>\n Effect.succeed(mcpErrorResult(`MCP tool failed: ${error.message}`))\n )\n )\n\n return successResponse(request.id, mcpResultFromExecutionResult(result))\n }\n\n default:\n return errorResponse(request.id, -32_601, `Method not found: ${request.method}`)\n }\n }).pipe(Effect.catch(error => Effect.succeed(protocolErrorResponse(request.id, error))))\n\n const handleLine = (line: string) =>\n Effect.gen(function* () {\n const decoded: DecodedLine = yield* decodeMessage(line).pipe(\n Effect.map(decodedMessage),\n Effect.catch(error =>\n encodeJson(protocolErrorResponse(null, error)).pipe(\n Effect.map(response => decodedResponse(Option.some(response)))\n )\n )\n )\n\n if (Predicate.isTagged(decoded, 'Response')) {\n return decoded.response\n }\n\n const { message } = decoded\n\n if (!isRequest(message)) {\n return Option.none<string>()\n }\n\n const response = yield* handleRequest(message)\n const encoded = yield* encodeJson(response)\n\n return Option.some(encoded)\n })\n\n const handleJson = (body: string) =>\n Effect.gen(function* () {\n const response = yield* handleLine(body)\n\n if (Option.isNone(response)) {\n return yield* encodeJson(errorResponse(null, -32_600, 'Notifications have no response'))\n }\n\n return response.value\n })\n\n const handleHttpRequest = (request: Request) =>\n Effect.gen(function* () {\n const targetHostname = new URL(request.url).hostname\n\n const rejected = originValidationResponse(\n request,\n Array.from(input.allowedOriginHostnames ?? [targetHostname])\n )\n\n if (rejected !== undefined) {\n return rejected\n }\n\n if (!request.headers.has('mcp-protocol-version')) {\n if (request.method !== 'POST') {\n const body = yield* methodNotAllowedBody()\n\n return jsonResponse(body, { status: 405, headers: { allow: 'POST' } })\n }\n\n const body = yield* Effect.tryPromise({\n try: () => request.text(),\n catch: error => `Could not read request body: ${unknownToMessage(error)}`\n }).pipe(Effect.result)\n\n if (Result.isFailure(body)) {\n return jsonResponse(yield* badRequestBody(body.failure))\n }\n\n const responseBody = yield* handleJson(body.success).pipe(\n Effect.catch(error => badRequestBody(error.message))\n )\n\n return jsonResponse(responseBody)\n }\n\n const context = yield* Effect.context<R>()\n const handler = createMcpHandler(() => makeSdkServer(context))\n\n return yield* Effect.acquireUseRelease(\n Effect.succeed(handler),\n current =>\n Effect.tryPromise(() => current.fetch(request)).pipe(\n Effect.catch(error =>\n badRequestBody(unknownToMessage(error)).pipe(\n Effect.map(body => jsonResponse(body, { status: 400 }))\n )\n )\n ),\n current => Effect.promise(() => current.close()).pipe(Effect.catch(() => Effect.void))\n )\n })\n\n return { handleLine, handleJson, handleHttpRequest }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.mjs","names":["Arr","SdkMcpServer"],"sources":["../../src/server/server.ts"],"sourcesContent":["import { Array as Arr, Effect, Match, Option, Predicate, Result } from 'effect'\nimport type { Context } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n McpServer as SdkMcpServer,\n createMcpHandler,\n fromJsonSchema,\n originValidationResponse,\n type CallToolResult as SdkCallToolResult,\n type ContentBlock as SdkContentBlock\n} from '@modelcontextprotocol/server'\nimport {\n ToolCall,\n ToolResult,\n attachmentSourceBase64,\n attachmentSourcePreview,\n filePartText,\n contentParts,\n type ContentPart,\n type ToolDef\n} from '@yolk-sdk/agent/protocol'\nimport { legacyMcpProtocolVersion } from '@yolk-sdk/mcp/client'\nimport { McpServerError } from './errors.ts'\n\ntype JsonRpcRequest = {\n readonly jsonrpc: '2.0'\n readonly id: string | number\n readonly method: string\n readonly params?: unknown\n}\n\ntype JsonRpcNotification = {\n readonly jsonrpc: '2.0'\n readonly method: string\n readonly params?: unknown\n}\n\ntype JsonRpcResponse = {\n readonly jsonrpc: '2.0'\n readonly id: string | number | null\n readonly result?: unknown\n readonly error?: {\n readonly code: number\n readonly message: string\n }\n}\n\nconst JsonRpcRequestSchema = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n id: Schema.Union([Schema.String, Schema.Number]),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nconst JsonRpcNotificationSchema = Schema.Struct({\n jsonrpc: Schema.Literal('2.0'),\n method: Schema.String,\n params: Schema.optional(Schema.Unknown)\n})\n\nconst CallToolParamsSchema = Schema.Struct({\n name: Schema.String,\n arguments: Schema.optional(Schema.Unknown)\n})\n\nconst JsonRpcMessageSchema = Schema.Union([JsonRpcRequestSchema, JsonRpcNotificationSchema])\n\ntype JsonRpcMessage = typeof JsonRpcMessageSchema.Type\n\nconst DecodedMessageLine = Schema.TaggedStruct('Message', {\n message: Schema.Unknown\n})\n\nconst DecodedResponseLine = Schema.TaggedStruct('Response', {\n response: Schema.Unknown\n})\n\ntype DecodedLine =\n | {\n readonly _tag: 'Message'\n readonly message: JsonRpcMessage\n }\n | {\n readonly _tag: 'Response'\n readonly response: Option.Option<string>\n }\n\nconst decodedMessage = (message: JsonRpcMessage): DecodedLine => ({\n ...DecodedMessageLine.make({ message }),\n message\n})\n\nconst decodedResponse = (response: Option.Option<string>): DecodedLine => ({\n ...DecodedResponseLine.make({ response }),\n response\n})\n\nconst decodeJson = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))\n\nconst decodeJsonRpcMessage = Schema.decodeUnknownEffect(JsonRpcMessageSchema)\n\nconst decodeCallToolParams = Schema.decodeUnknownEffect(CallToolParamsSchema)\n\nconst encodeJson = (value: JsonRpcResponse) =>\n Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(value).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Could not encode MCP response: ${String(error)}`,\n cause: 'encoding'\n })\n )\n )\n\nconst decodeMessage = (line: string) =>\n decodeJson(line).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Malformed MCP JSON: ${String(error)}`,\n cause: 'parse'\n })\n ),\n Effect.flatMap(value =>\n decodeJsonRpcMessage(value).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Invalid MCP JSON-RPC message: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n )\n )\n\nconst successResponse = (id: string | number, result: unknown): JsonRpcResponse => ({\n jsonrpc: '2.0',\n id,\n result\n})\n\nconst errorResponse = (\n id: string | number | null,\n code: number,\n message: string\n): JsonRpcResponse => ({\n jsonrpc: '2.0',\n id,\n error: { code, message }\n})\n\nconst unknownToMessage = (error: unknown) =>\n error instanceof Error ? error.message : String(error)\n\nconst isRequest = (message: JsonRpcRequest | JsonRpcNotification): message is JsonRpcRequest =>\n 'id' in message\n\nconst protocolErrorCode = (error: McpServerError) => {\n switch (error.cause) {\n case 'parse':\n return -32_700\n case 'validation':\n return -32_600\n case 'protocol':\n return -32_603\n case 'tool_error':\n case 'encoding':\n return -32_000\n }\n}\n\nconst protocolErrorResponse = (id: string | number | null, error: McpServerError) =>\n errorResponse(id, protocolErrorCode(error), error.message)\n\nconst documentResourceUri = (filename: string) => `file:///${encodeURIComponent(filename)}`\n\nconst mcpContentBlockFromPart = (part: ContentPart): SdkContentBlock =>\n Match.value(part).pipe(\n Match.withReturnType<SdkContentBlock>(),\n Match.tag('Text', current => ({ type: 'text', text: current.text })),\n Match.tag('Image', current =>\n Option.match(attachmentSourceBase64(current.source), {\n onNone: () => ({\n type: 'text',\n text: `Image attachment: ${attachmentSourcePreview(current.source)}`\n }),\n onSome: data => ({ type: 'image', data, mimeType: current.mimeType })\n })\n ),\n Match.tag('Document', current =>\n Option.match(attachmentSourceBase64(current.source), {\n onNone: () => ({\n type: 'text',\n text: `Document attachment: ${attachmentSourcePreview(current.source)}`\n }),\n onSome: data => ({\n type: 'resource',\n resource: {\n uri: documentResourceUri(current.filename),\n name: current.title ?? current.filename,\n mimeType: current.mimeType,\n blob: data\n }\n })\n })\n ),\n Match.tag('Audio', current =>\n Option.match(attachmentSourceBase64(current.source), {\n onNone: () => ({\n type: 'text',\n text: `Audio attachment: ${attachmentSourcePreview(current.source)}`\n }),\n onSome: data => ({ type: 'audio', data, mimeType: current.mimeType })\n })\n ),\n // Inline file bytes leave as an embedded resource; a captured file only as its label.\n Match.tag('File', current =>\n Option.match(attachmentSourceBase64(current.source), {\n onNone: () => ({ type: 'text', text: filePartText(current) }),\n onSome: data => ({\n type: 'resource',\n resource: {\n uri: documentResourceUri(current.filename ?? 'file'),\n mimeType: current.mimeType,\n blob: data\n }\n })\n })\n ),\n Match.exhaustive\n )\n\nconst mcpResultFromToolResult = (result: ToolResult): SdkCallToolResult => {\n const content = Arr.map(contentParts(result.content), mcpContentBlockFromPart)\n const base = result.isError === undefined ? { content } : { content, isError: result.isError }\n\n return result.structuredContent === undefined\n ? base\n : { ...base, structuredContent: result.structuredContent }\n}\n\nconst mcpErrorResult = (message: string): SdkCallToolResult => ({\n content: [{ type: 'text', text: message }],\n isError: true\n})\n\nconst mcpResultFromExecutionResult = (\n result: ToolResult | ReturnType<typeof mcpErrorResult>\n): SdkCallToolResult => (result instanceof ToolResult ? mcpResultFromToolResult(result) : result)\n\nconst toolListItem = (tool: ToolDef) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters\n})\n\nexport type McpServerTool<R = never> = {\n readonly def: ToolDef\n readonly execute: (call: ToolCall) => Effect.Effect<ToolResult, McpServerError, R>\n}\n\nexport type McpToolServer<R = never> = {\n readonly handleLine: (line: string) => Effect.Effect<Option.Option<string>, McpServerError, R>\n readonly handleJson: (body: string) => Effect.Effect<string, McpServerError, R>\n readonly handleHttpRequest: (request: Request) => Effect.Effect<Response, never, R>\n}\n\nconst jsonResponse = (body: string, init?: ResponseInit) =>\n new Response(body, {\n ...init,\n headers: {\n 'content-type': 'application/json',\n ...(init?.headers ?? {})\n }\n })\n\nconst methodNotAllowedBody = () =>\n encodeJson(errorResponse(null, -32_600, 'Method not allowed')).pipe(\n Effect.orElseSucceed(\n () => '{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32600,\"message\":\"Method not allowed\"}}'\n )\n )\n\nconst badRequestBody = (message: string) =>\n encodeJson(errorResponse(null, -32_600, message)).pipe(\n Effect.orElseSucceed(\n () => '{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32600,\"message\":\"Bad request\"}}'\n )\n )\n\nexport const makeMcpToolServer = <R>(input: {\n readonly name: string\n readonly version: string\n readonly tools: ReadonlyArray<McpServerTool<R>>\n readonly allowedOriginHostnames?: ReadonlyArray<string>\n}): McpToolServer<R> => {\n const findTool = (name: string) => Arr.findFirst(input.tools, tool => tool.def.name === name)\n\n const toolInputSchemas = input.tools.map(tool => ({\n tool,\n schema: Schema.decodeUnknownOption(Schema.Record(Schema.String, Schema.Unknown))(\n tool.def.parameters\n ).pipe(Option.getOrElse(() => ({ type: 'object', additionalProperties: true })))\n }))\n\n const makeSdkServer = (context: Context.Context<R>) => {\n const server = new SdkMcpServer(\n { name: input.name, version: input.version },\n {\n cacheHints: {\n 'server/discover': { ttlMs: 0, cacheScope: 'private' },\n 'tools/list': { ttlMs: 0, cacheScope: 'private' }\n }\n }\n )\n\n for (const { schema, tool } of toolInputSchemas) {\n server.registerTool(\n tool.def.name,\n {\n description: tool.def.description,\n inputSchema: fromJsonSchema(schema)\n },\n async (args, sdkContext) => {\n const result = await Effect.runPromiseWith(context)(\n tool\n .execute(\n ToolCall.make({\n id: String(sdkContext.mcpReq.id),\n name: tool.def.name,\n params: args\n })\n )\n .pipe(\n Effect.catch(error =>\n Effect.succeed(mcpErrorResult(`MCP tool failed: ${error.message}`))\n )\n )\n )\n\n return mcpResultFromExecutionResult(result)\n }\n )\n }\n\n return server\n }\n\n const handleRequest = (request: JsonRpcRequest) =>\n Effect.gen(function* () {\n switch (request.method) {\n case 'initialize':\n return successResponse(request.id, {\n protocolVersion: legacyMcpProtocolVersion,\n capabilities: { tools: {} },\n serverInfo: { name: input.name, version: input.version }\n })\n case 'tools/list':\n return successResponse(request.id, {\n tools: input.tools.map(tool => toolListItem(tool.def))\n })\n case 'tools/call': {\n const params = yield* decodeCallToolParams(request.params).pipe(\n Effect.mapError(\n error =>\n new McpServerError({\n message: `Invalid tools/call params: ${String(error)}`,\n cause: 'validation'\n })\n )\n )\n\n const tool = findTool(params.name)\n\n if (Option.isNone(tool)) {\n return errorResponse(request.id, -32_602, `Unknown tool: ${params.name}`)\n }\n\n const result = yield* tool.value\n .execute(\n ToolCall.make({\n id: String(request.id),\n name: params.name,\n params: params.arguments ?? {}\n })\n )\n .pipe(\n Effect.catch(error =>\n Effect.succeed(mcpErrorResult(`MCP tool failed: ${error.message}`))\n )\n )\n\n return successResponse(request.id, mcpResultFromExecutionResult(result))\n }\n\n default:\n return errorResponse(request.id, -32_601, `Method not found: ${request.method}`)\n }\n }).pipe(Effect.catch(error => Effect.succeed(protocolErrorResponse(request.id, error))))\n\n const handleLine = (line: string) =>\n Effect.gen(function* () {\n const decoded: DecodedLine = yield* decodeMessage(line).pipe(\n Effect.map(decodedMessage),\n Effect.catch(error =>\n encodeJson(protocolErrorResponse(null, error)).pipe(\n Effect.map(response => decodedResponse(Option.some(response)))\n )\n )\n )\n\n if (Predicate.isTagged(decoded, 'Response')) {\n return decoded.response\n }\n\n const { message } = decoded\n\n if (!isRequest(message)) {\n return Option.none<string>()\n }\n\n const response = yield* handleRequest(message)\n const encoded = yield* encodeJson(response)\n\n return Option.some(encoded)\n })\n\n const handleJson = (body: string) =>\n Effect.gen(function* () {\n const response = yield* handleLine(body)\n\n if (Option.isNone(response)) {\n return yield* encodeJson(errorResponse(null, -32_600, 'Notifications have no response'))\n }\n\n return response.value\n })\n\n const handleHttpRequest = (request: Request) =>\n Effect.gen(function* () {\n const targetHostname = new URL(request.url).hostname\n\n const rejected = originValidationResponse(\n request,\n Array.from(input.allowedOriginHostnames ?? [targetHostname])\n )\n\n if (rejected !== undefined) {\n return rejected\n }\n\n if (!request.headers.has('mcp-protocol-version')) {\n if (request.method !== 'POST') {\n const body = yield* methodNotAllowedBody()\n\n return jsonResponse(body, { status: 405, headers: { allow: 'POST' } })\n }\n\n const body = yield* Effect.tryPromise({\n try: () => request.text(),\n catch: error => `Could not read request body: ${unknownToMessage(error)}`\n }).pipe(Effect.result)\n\n if (Result.isFailure(body)) {\n return jsonResponse(yield* badRequestBody(body.failure))\n }\n\n const responseBody = yield* handleJson(body.success).pipe(\n Effect.catch(error => badRequestBody(error.message))\n )\n\n return jsonResponse(responseBody)\n }\n\n const context = yield* Effect.context<R>()\n const handler = createMcpHandler(() => makeSdkServer(context))\n\n return yield* Effect.acquireUseRelease(\n Effect.succeed(handler),\n current =>\n Effect.tryPromise(() => current.fetch(request)).pipe(\n Effect.catch(error =>\n badRequestBody(unknownToMessage(error)).pipe(\n Effect.map(body => jsonResponse(body, { status: 400 }))\n )\n )\n ),\n current => Effect.promise(() => current.close()).pipe(Effect.catch(() => Effect.void))\n )\n })\n\n return { handleLine, handleJson, handleHttpRequest }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yolk-sdk/mcp",
|
|
3
|
-
"version": "0.1.0-canary.
|
|
3
|
+
"version": "0.1.0-canary.115",
|
|
4
4
|
"description": "MCP v2 client/server/protocol APIs, Effect/Yolk adapters, legacy compatibility, and experimental conformance cases.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
"@modelcontextprotocol/server": "2.0.0",
|
|
86
86
|
"effect": "4.0.0",
|
|
87
87
|
"eventsource-parser": "^3.0.0",
|
|
88
|
-
"@yolk-sdk/agent": "^0.1.0-canary.
|
|
89
|
-
"@yolk-sdk/conformance": "^0.1.0-canary.
|
|
88
|
+
"@yolk-sdk/agent": "^0.1.0-canary.115",
|
|
89
|
+
"@yolk-sdk/conformance": "^0.1.0-canary.115"
|
|
90
90
|
},
|
|
91
91
|
"scripts": {
|
|
92
92
|
"build": "tsdown",
|
package/src/client/protocol.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Array as Arr, Effect, Option, Predicate } from 'effect'
|
|
|
2
2
|
import * as Schema from 'effect/Schema'
|
|
3
3
|
import {
|
|
4
4
|
AudioPart,
|
|
5
|
+
FilePart,
|
|
5
6
|
ImagePart,
|
|
6
7
|
TextPart,
|
|
7
8
|
ToolDef,
|
|
@@ -294,17 +295,36 @@ const fallbackTextForContentBlock = (block: GenericContentBlock) => {
|
|
|
294
295
|
}
|
|
295
296
|
}
|
|
296
297
|
|
|
297
|
-
const
|
|
298
|
+
const resourceFilename = (uri: string) => {
|
|
299
|
+
const segments = (uri.split(/[?#]/u, 1)[0] ?? '').split('/').filter(part => part.length > 0)
|
|
300
|
+
const segment = segments[segments.length - 1]
|
|
301
|
+
|
|
302
|
+
if (segment === undefined || segment.endsWith(':')) return undefined
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
return decodeURIComponent(segment)
|
|
306
|
+
} catch {
|
|
307
|
+
return segment
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Embedded text stays text; a blob becomes a file part that tool resolution captures (ADR 0009),
|
|
312
|
+
// so its base64 never reaches the model.
|
|
313
|
+
const embeddedResourcePart = (block: GenericContentBlock): Option.Option<ContentPart> =>
|
|
298
314
|
Schema.decodeUnknownOption(EmbeddedResourceContentBlock)(block).pipe(
|
|
299
|
-
Option.flatMap(({ resource }) => {
|
|
300
|
-
if (resource.text !== undefined) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
315
|
+
Option.flatMap(({ resource }): Option.Option<ContentPart> => {
|
|
316
|
+
if (resource.text !== undefined) return Option.some(TextPart.make({ text: resource.text }))
|
|
317
|
+
|
|
318
|
+
if (resource.blob === undefined) return Option.none()
|
|
319
|
+
|
|
320
|
+
const mimeType = resource.mimeType ?? 'application/octet-stream'
|
|
321
|
+
const filename = resource.uri === undefined ? undefined : resourceFilename(resource.uri)
|
|
322
|
+
|
|
323
|
+
return Option.some(
|
|
324
|
+
filename === undefined
|
|
325
|
+
? FilePart.make({ source: inlineBase64Source(resource.blob), mimeType })
|
|
326
|
+
: FilePart.make({ source: inlineBase64Source(resource.blob), mimeType, filename })
|
|
327
|
+
)
|
|
308
328
|
})
|
|
309
329
|
)
|
|
310
330
|
|
|
@@ -357,11 +377,9 @@ const contentPartFromBlock = (block: GenericContentBlock): ContentPart => {
|
|
|
357
377
|
}
|
|
358
378
|
|
|
359
379
|
if (type === 'resource') {
|
|
360
|
-
return
|
|
361
|
-
text:
|
|
362
|
-
|
|
363
|
-
)
|
|
364
|
-
})
|
|
380
|
+
return Option.getOrElse(embeddedResourcePart(block), () =>
|
|
381
|
+
TextPart.make({ text: fallbackTextForContentBlock(block) })
|
|
382
|
+
)
|
|
365
383
|
}
|
|
366
384
|
|
|
367
385
|
if (type === 'resource_link') {
|
package/src/server/server.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
ToolResult,
|
|
15
15
|
attachmentSourceBase64,
|
|
16
16
|
attachmentSourcePreview,
|
|
17
|
+
filePartText,
|
|
17
18
|
contentParts,
|
|
18
19
|
type ContentPart,
|
|
19
20
|
type ToolDef
|
|
@@ -213,6 +214,20 @@ const mcpContentBlockFromPart = (part: ContentPart): SdkContentBlock =>
|
|
|
213
214
|
onSome: data => ({ type: 'audio', data, mimeType: current.mimeType })
|
|
214
215
|
})
|
|
215
216
|
),
|
|
217
|
+
// Inline file bytes leave as an embedded resource; a captured file only as its label.
|
|
218
|
+
Match.tag('File', current =>
|
|
219
|
+
Option.match(attachmentSourceBase64(current.source), {
|
|
220
|
+
onNone: () => ({ type: 'text', text: filePartText(current) }),
|
|
221
|
+
onSome: data => ({
|
|
222
|
+
type: 'resource',
|
|
223
|
+
resource: {
|
|
224
|
+
uri: documentResourceUri(current.filename ?? 'file'),
|
|
225
|
+
mimeType: current.mimeType,
|
|
226
|
+
blob: data
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
),
|
|
216
231
|
Match.exhaustive
|
|
217
232
|
)
|
|
218
233
|
|