tiny-stdio-mcp-server 0.1.0 → 0.1.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/README.md +180 -0
- package/dist/content/convert.d.ts +7 -1
- package/dist/content/convert.js +21 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -3
- package/dist/server.d.ts +3 -1
- package/dist/server.js +33 -20
- package/dist/types.d.ts +12 -4
- package/dist/types.js +9 -1
- package/package.json +13 -4
- package/dist/testing.d.ts +0 -7
- package/dist/testing.js +0 -20
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# tiny-stdio-mcp-server
|
|
2
|
+
|
|
3
|
+
Minimal [Model Context Protocol](https://modelcontextprotocol.io) server for Node.js. Zero runtime dependencies, type-safe tool definitions, rich content helpers for images/audio/files.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install tiny-stdio-mcp-server
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createServer, defineSchema } from "tiny-stdio-mcp-server";
|
|
15
|
+
|
|
16
|
+
const schema = defineSchema({
|
|
17
|
+
text: { type: "string", description: "Text to reverse" },
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
createServer({ name: "my-server", version: "1.0.0" })
|
|
21
|
+
.tool("reverse", "Reverse a string", schema, ({ text }) => {
|
|
22
|
+
return text.split("").reverse().join("");
|
|
23
|
+
})
|
|
24
|
+
.listen();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Run it:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
node my-server.js
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Any MCP client (Claude Code, Codex, etc.) can connect to it over stdio.
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
|
|
37
|
+
### `createServer(options)`
|
|
38
|
+
|
|
39
|
+
Creates a new MCP server.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
const server = createServer({ name: "my-server", version: "1.0.0" });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `.tool(name, description, schema, handler)`
|
|
46
|
+
|
|
47
|
+
Register a tool. The handler receives typed args matching the schema and returns a string, content helper, or array of either.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const schema = defineSchema({
|
|
51
|
+
query: { type: "string", description: "Search query" },
|
|
52
|
+
limit: { type: "number", description: "Max results", optional: true },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
server.tool("search", "Search for things", schema, async ({ query, limit }) => {
|
|
56
|
+
// `query` is string, `limit` is number | undefined
|
|
57
|
+
return `Found results for: ${query}`;
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `.listen()`
|
|
62
|
+
|
|
63
|
+
Start listening on stdin/stdout (standard MCP stdio transport).
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
await server.listen();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `.connect(transport)`
|
|
70
|
+
|
|
71
|
+
Connect to a custom readable/writable stream pair.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
await server.connect({ readable: process.stdin, writable: process.stdout });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `.connectSDK(transport)`
|
|
78
|
+
|
|
79
|
+
Connect using an SDK-compatible in-memory transport (for testing).
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
await server.connectSDK(sdkTransport);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `.removeTool(name)` / `.notifyToolsChanged()`
|
|
86
|
+
|
|
87
|
+
Dynamically add/remove tools at runtime and notify connected clients.
|
|
88
|
+
|
|
89
|
+
## `defineSchema(definition)`
|
|
90
|
+
|
|
91
|
+
Type-safe schema builder. Returns a JSON Schema object with inferred TypeScript types.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const schema = defineSchema({
|
|
95
|
+
name: { type: "string", description: "User name" },
|
|
96
|
+
age: { type: "number", description: "User age", optional: true },
|
|
97
|
+
});
|
|
98
|
+
// Handler receives: { name: string; age?: number }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Supported types: `string`, `number`, `boolean`, `object`, `array`.
|
|
102
|
+
|
|
103
|
+
## Content helpers
|
|
104
|
+
|
|
105
|
+
Tool handlers can return rich content beyond plain text.
|
|
106
|
+
|
|
107
|
+
### Images
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { Image } from "tiny-stdio-mcp-server";
|
|
111
|
+
|
|
112
|
+
server.tool("screenshot", "Take a screenshot", schema, async () => {
|
|
113
|
+
return Image.fromBase64(base64Data, "image/png");
|
|
114
|
+
// or: await Image.fromUrl("https://example.com/image.png")
|
|
115
|
+
// or: Image.fromBytes(uint8Array)
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Supported formats: PNG, JPEG, GIF, WebP.
|
|
120
|
+
|
|
121
|
+
### Audio
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { Audio } from "tiny-stdio-mcp-server";
|
|
125
|
+
|
|
126
|
+
server.tool("speak", "Text to speech", schema, async () => {
|
|
127
|
+
return Audio.fromBase64(base64Data, "audio/mpeg");
|
|
128
|
+
// or: await Audio.fromUrl("https://example.com/audio.mp3")
|
|
129
|
+
// or: Audio.fromBytes(uint8Array, "mp3")
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Supported formats: MP3, WAV, OGG, M4A.
|
|
134
|
+
|
|
135
|
+
### Files
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { File } from "tiny-stdio-mcp-server";
|
|
139
|
+
|
|
140
|
+
server.tool("export", "Export data", schema, async () => {
|
|
141
|
+
return File.fromText(csvContent, "text/csv");
|
|
142
|
+
// or: File.fromBytes(uint8Array, "application/pdf")
|
|
143
|
+
// or: await File.fromUrl("https://example.com/report.pdf")
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Mixed content
|
|
148
|
+
|
|
149
|
+
Return arrays to send multiple content blocks:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
server.tool("analyze", "Analyze image", schema, async () => {
|
|
153
|
+
const image = await Image.fromUrl(url);
|
|
154
|
+
return [image, "Analysis complete: found 3 objects"];
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Testing
|
|
159
|
+
|
|
160
|
+
Use `createTestPair` with the official MCP SDK for in-memory testing:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { createTestPair } from "tiny-stdio-mcp-server/testing";
|
|
164
|
+
|
|
165
|
+
const server = createServer({ name: "test", version: "1.0.0" })
|
|
166
|
+
.tool("ping", "Ping", defineSchema({}), () => "pong");
|
|
167
|
+
|
|
168
|
+
const { client, cleanup } = await createTestPair(server);
|
|
169
|
+
|
|
170
|
+
const result = await client.callTool({ name: "ping", arguments: {} });
|
|
171
|
+
// result.content === [{ type: "text", text: "pong" }]
|
|
172
|
+
|
|
173
|
+
await cleanup();
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Requires `@modelcontextprotocol/sdk` as a dev dependency.
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT
|
|
@@ -6,5 +6,11 @@ export interface TextContent {
|
|
|
6
6
|
text: string;
|
|
7
7
|
}
|
|
8
8
|
export type ContentBlock = TextContent | ImageContent | AudioContent | EmbeddedResource;
|
|
9
|
-
|
|
9
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
10
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
11
|
+
export type JsonObject = {
|
|
12
|
+
[key: string]: JsonValue;
|
|
13
|
+
};
|
|
14
|
+
export type ToolReturn = undefined | JsonPrimitive | JsonObject | Image | Audio | File | ContentBlock | Array<undefined | JsonPrimitive | JsonObject | Image | Audio | File | ContentBlock>;
|
|
10
15
|
export declare function toContentBlocks(result: ToolReturn): ContentBlock[];
|
|
16
|
+
export {};
|
package/dist/content/convert.js
CHANGED
|
@@ -2,8 +2,11 @@ import { Image } from "./image.js";
|
|
|
2
2
|
import { Audio } from "./audio.js";
|
|
3
3
|
import { File } from "./file.js";
|
|
4
4
|
function convertSingleValue(value) {
|
|
5
|
-
if (typeof value === "string") {
|
|
6
|
-
return { type: "text", text: value };
|
|
5
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
6
|
+
return { type: "text", text: String(value) };
|
|
7
|
+
}
|
|
8
|
+
if (value === null) {
|
|
9
|
+
return { type: "text", text: "null" };
|
|
7
10
|
}
|
|
8
11
|
if (value instanceof Image) {
|
|
9
12
|
return value.toContentBlock();
|
|
@@ -14,12 +17,26 @@ function convertSingleValue(value) {
|
|
|
14
17
|
if (value instanceof File) {
|
|
15
18
|
return value.toContentBlock();
|
|
16
19
|
}
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
if (isContentBlock(value)) {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
return { type: "text", text: JSON.stringify(value) };
|
|
19
24
|
}
|
|
20
25
|
export function toContentBlocks(result) {
|
|
26
|
+
if (result === undefined) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
21
29
|
if (Array.isArray(result)) {
|
|
22
30
|
return result.flatMap((item) => toContentBlocks(item));
|
|
23
31
|
}
|
|
24
32
|
return [convertSingleValue(result)];
|
|
25
33
|
}
|
|
34
|
+
function isContentBlock(value) {
|
|
35
|
+
if (!("type" in value) || typeof value.type !== "string") {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return (value.type === "text" ||
|
|
39
|
+
value.type === "image" ||
|
|
40
|
+
value.type === "audio" ||
|
|
41
|
+
value.type === "resource");
|
|
42
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,8 @@ export { createServer } from "./server.js";
|
|
|
2
2
|
export type { Server } from "./server.js";
|
|
3
3
|
export { defineSchema } from "./schema.js";
|
|
4
4
|
export type { TypedSchema } from "./schema.js";
|
|
5
|
-
export { createTestPair } from "./testing.js";
|
|
6
|
-
export type { TestPair } from "./testing.js";
|
|
7
5
|
export { Image, Audio, File, toContentBlocks, fileTypeFromBuffer, } from "./content/index.js";
|
|
8
6
|
export type { ImageContent, AudioContent, EmbeddedResource, TextResourceContents, BlobResourceContents, ContentBlock, TextContent, FileTypeResult, } from "./content/index.js";
|
|
9
7
|
export type { ToolReturn } from "./content/index.js";
|
|
10
|
-
export type { ServerOptions, ToolHandler, ToolDefinition, Tool, CallToolResult, ContentItem, JSONSchema, JSONSchemaProperty, Transport, SDKTransport, JSONRPCRequest, JSONRPCResponse, JSONRPCError, JSONRPCMessage, JSONRPCNotification, InitializeResult, } from "./types.js";
|
|
11
|
-
export { JSON_RPC_ERROR_CODES } from "./types.js";
|
|
8
|
+
export type { ServerOptions, ToolHandler, ToolDefinition, Tool, CallToolResult, HandleResult, ContentItem, JSONSchema, JSONSchemaProperty, Transport, SDKTransport, JSONRPCRequest, JSONRPCResponse, JSONRPCError, JSONRPCMessage, JSONRPCNotification, InitializeResult, } from "./types.js";
|
|
9
|
+
export { JSON_RPC_ERROR_CODES, ToolError } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
export { createServer } from "./server.js";
|
|
3
3
|
// Schema
|
|
4
4
|
export { defineSchema } from "./schema.js";
|
|
5
|
-
// Testing utilities
|
|
6
|
-
export { createTestPair } from "./testing.js";
|
|
7
5
|
// Content helpers
|
|
8
6
|
export { Image, Audio, File, toContentBlocks, fileTypeFromBuffer, } from "./content/index.js";
|
|
9
|
-
export { JSON_RPC_ERROR_CODES } from "./types.js";
|
|
7
|
+
export { JSON_RPC_ERROR_CODES, ToolError } from "./types.js";
|
package/dist/server.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type { ServerOptions, ToolHandler, Transport, SDKTransport } from "./types.js";
|
|
1
|
+
import type { ServerOptions, ToolHandler, HandleResult, Transport, SDKTransport, JSONRPCNotification } from "./types.js";
|
|
2
2
|
import type { TypedSchema } from "./schema.js";
|
|
3
3
|
export interface Server {
|
|
4
4
|
tool<T>(name: string, description: string, inputSchema: TypedSchema<T>, handler: ToolHandler<T>): Server;
|
|
5
|
+
onNotification(listener: (notification: JSONRPCNotification) => void): () => void;
|
|
5
6
|
removeTool(name: string): boolean;
|
|
6
7
|
notifyToolsChanged(): Promise<void>;
|
|
8
|
+
handleMessage(method: string, params?: Record<string, unknown>): Promise<HandleResult>;
|
|
7
9
|
listen(): Promise<void>;
|
|
8
10
|
connect(transport: Transport): Promise<void>;
|
|
9
11
|
connectSDK(transport: SDKTransport): Promise<void>;
|
package/dist/server.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import * as readline from "readline";
|
|
2
|
-
import { JSON_RPC_ERROR_CODES } from "./types.js";
|
|
2
|
+
import { JSON_RPC_ERROR_CODES, ToolError } from "./types.js";
|
|
3
3
|
import { parseMessage, formatSuccessResponse, formatErrorResponse, } from "./jsonrpc.js";
|
|
4
4
|
import { toContentBlocks } from "./content/convert.js";
|
|
5
5
|
const PROTOCOL_VERSION = "2025-11-25";
|
|
6
6
|
export function createServer(options) {
|
|
7
7
|
const tools = new Map();
|
|
8
|
+
const notificationListeners = new Set();
|
|
8
9
|
let initialized = false;
|
|
9
|
-
|
|
10
|
-
let activeSDKTransport = null;
|
|
11
|
-
const handleRequest = async (method, params) => {
|
|
10
|
+
const handleMessage = async (method, params) => {
|
|
12
11
|
// Allow ping and initialize before initialization
|
|
13
12
|
if (method === "ping") {
|
|
14
13
|
return { result: {} };
|
|
@@ -81,6 +80,14 @@ export function createServer(options) {
|
|
|
81
80
|
return { result };
|
|
82
81
|
}
|
|
83
82
|
catch (err) {
|
|
83
|
+
if (err instanceof ToolError) {
|
|
84
|
+
return {
|
|
85
|
+
error: {
|
|
86
|
+
code: err.code,
|
|
87
|
+
message: err.message,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
84
91
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
85
92
|
const result = {
|
|
86
93
|
content: [{ type: "text", text: `Error: ${errorMessage}` }],
|
|
@@ -103,7 +110,7 @@ export function createServer(options) {
|
|
|
103
110
|
return;
|
|
104
111
|
}
|
|
105
112
|
const { request, isNotification } = parsed;
|
|
106
|
-
const { result, error } = await
|
|
113
|
+
const { result, error } = await server.handleMessage(request.method, request.params);
|
|
107
114
|
if (isNotification) {
|
|
108
115
|
return;
|
|
109
116
|
}
|
|
@@ -115,16 +122,13 @@ export function createServer(options) {
|
|
|
115
122
|
write(formatSuccessResponse(requestWithId.id, result) + "\n");
|
|
116
123
|
}
|
|
117
124
|
};
|
|
118
|
-
const
|
|
125
|
+
const broadcastNotification = (method) => {
|
|
119
126
|
const notification = {
|
|
120
127
|
jsonrpc: "2.0",
|
|
121
128
|
method,
|
|
122
129
|
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
else if (activeTransport) {
|
|
127
|
-
activeTransport.writable.write(JSON.stringify(notification) + "\n");
|
|
130
|
+
for (const listener of notificationListeners) {
|
|
131
|
+
listener(notification);
|
|
128
132
|
}
|
|
129
133
|
};
|
|
130
134
|
const server = {
|
|
@@ -137,14 +141,21 @@ export function createServer(options) {
|
|
|
137
141
|
});
|
|
138
142
|
return server;
|
|
139
143
|
},
|
|
144
|
+
onNotification(listener) {
|
|
145
|
+
notificationListeners.add(listener);
|
|
146
|
+
return () => {
|
|
147
|
+
notificationListeners.delete(listener);
|
|
148
|
+
};
|
|
149
|
+
},
|
|
140
150
|
removeTool(name) {
|
|
141
151
|
return tools.delete(name);
|
|
142
152
|
},
|
|
143
153
|
async notifyToolsChanged() {
|
|
144
154
|
if (initialized) {
|
|
145
|
-
|
|
155
|
+
broadcastNotification("notifications/tools/list_changed");
|
|
146
156
|
}
|
|
147
157
|
},
|
|
158
|
+
handleMessage,
|
|
148
159
|
async listen() {
|
|
149
160
|
return server.connect({
|
|
150
161
|
readable: process.stdin,
|
|
@@ -152,9 +163,10 @@ export function createServer(options) {
|
|
|
152
163
|
});
|
|
153
164
|
},
|
|
154
165
|
async connect(transport) {
|
|
155
|
-
activeTransport = transport;
|
|
156
|
-
activeSDKTransport = null;
|
|
157
166
|
return new Promise((resolve) => {
|
|
167
|
+
const unsubscribe = server.onNotification((notification) => {
|
|
168
|
+
transport.writable.write(`${JSON.stringify(notification)}\n`);
|
|
169
|
+
});
|
|
158
170
|
const rl = readline.createInterface({
|
|
159
171
|
input: transport.readable,
|
|
160
172
|
crlfDelay: Infinity,
|
|
@@ -163,15 +175,16 @@ export function createServer(options) {
|
|
|
163
175
|
processLine(line, (data) => transport.writable.write(data));
|
|
164
176
|
});
|
|
165
177
|
rl.on("close", () => {
|
|
166
|
-
|
|
178
|
+
unsubscribe();
|
|
167
179
|
resolve();
|
|
168
180
|
});
|
|
169
181
|
});
|
|
170
182
|
},
|
|
171
183
|
async connectSDK(transport) {
|
|
172
|
-
activeSDKTransport = transport;
|
|
173
|
-
activeTransport = null;
|
|
174
184
|
return new Promise((resolve) => {
|
|
185
|
+
const unsubscribe = server.onNotification((notification) => {
|
|
186
|
+
void transport.send(notification);
|
|
187
|
+
});
|
|
175
188
|
transport.onmessage = async (message) => {
|
|
176
189
|
// Ignore responses (we only handle requests/notifications)
|
|
177
190
|
if (!("method" in message)) {
|
|
@@ -179,11 +192,11 @@ export function createServer(options) {
|
|
|
179
192
|
}
|
|
180
193
|
// Handle notifications (no id) - don't respond
|
|
181
194
|
if (!("id" in message) || message.id === undefined) {
|
|
182
|
-
await
|
|
195
|
+
await server.handleMessage(message.method, message.params);
|
|
183
196
|
return;
|
|
184
197
|
}
|
|
185
198
|
const request = message;
|
|
186
|
-
const { result, error } = await
|
|
199
|
+
const { result, error } = await server.handleMessage(request.method, request.params);
|
|
187
200
|
if (error) {
|
|
188
201
|
const response = {
|
|
189
202
|
jsonrpc: "2.0",
|
|
@@ -202,7 +215,7 @@ export function createServer(options) {
|
|
|
202
215
|
}
|
|
203
216
|
};
|
|
204
217
|
transport.onclose = () => {
|
|
205
|
-
|
|
218
|
+
unsubscribe();
|
|
206
219
|
resolve();
|
|
207
220
|
};
|
|
208
221
|
transport.start();
|
package/dist/types.d.ts
CHANGED
|
@@ -22,6 +22,10 @@ export declare const JSON_RPC_ERROR_CODES: {
|
|
|
22
22
|
readonly INVALID_PARAMS: -32602;
|
|
23
23
|
readonly INTERNAL_ERROR: -32603;
|
|
24
24
|
};
|
|
25
|
+
export declare class ToolError extends Error {
|
|
26
|
+
readonly code: number;
|
|
27
|
+
constructor(code: number, message: string);
|
|
28
|
+
}
|
|
25
29
|
export interface ToolsCapability {
|
|
26
30
|
listChanged?: boolean;
|
|
27
31
|
}
|
|
@@ -44,6 +48,13 @@ export interface CallToolResult {
|
|
|
44
48
|
content: ContentItem[];
|
|
45
49
|
isError?: boolean;
|
|
46
50
|
}
|
|
51
|
+
export interface HandleResult {
|
|
52
|
+
result?: unknown;
|
|
53
|
+
error?: {
|
|
54
|
+
code: number;
|
|
55
|
+
message: string;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
47
58
|
export type ContentItem = {
|
|
48
59
|
type: "text";
|
|
49
60
|
text: string;
|
|
@@ -80,10 +91,7 @@ export interface ServerOptions {
|
|
|
80
91
|
name: string;
|
|
81
92
|
version: string;
|
|
82
93
|
}
|
|
83
|
-
import type {
|
|
84
|
-
import type { Audio } from "./content/audio.js";
|
|
85
|
-
import type { File } from "./content/file.js";
|
|
86
|
-
export type ToolReturn = string | Image | Audio | File | ContentItem | Array<string | Image | Audio | File | ContentItem>;
|
|
94
|
+
import type { ToolReturn } from "./content/index.js";
|
|
87
95
|
export type ToolHandler<T = Record<string, unknown>> = (args: T) => Promise<ToolReturn> | ToolReturn;
|
|
88
96
|
export interface ToolDefinition<T = Record<string, unknown>> {
|
|
89
97
|
name: string;
|
package/dist/types.js
CHANGED
|
@@ -4,5 +4,13 @@ export const JSON_RPC_ERROR_CODES = {
|
|
|
4
4
|
INVALID_REQUEST: -32600,
|
|
5
5
|
METHOD_NOT_FOUND: -32601,
|
|
6
6
|
INVALID_PARAMS: -32602,
|
|
7
|
-
INTERNAL_ERROR: -32603
|
|
7
|
+
INTERNAL_ERROR: -32603
|
|
8
8
|
};
|
|
9
|
+
export class ToolError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
constructor(code, message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.name = "ToolError";
|
|
15
|
+
}
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-stdio-mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Minimal MCP server over stdio with typed tools and rich content helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./jsonrpc": {
|
|
14
|
+
"types": "./dist/jsonrpc.d.ts",
|
|
15
|
+
"import": "./dist/jsonrpc.js"
|
|
16
|
+
},
|
|
17
|
+
"./testing": {
|
|
18
|
+
"types": "./dist/testing.d.ts",
|
|
19
|
+
"import": "./dist/testing.js"
|
|
12
20
|
}
|
|
13
21
|
},
|
|
14
22
|
"scripts": {
|
|
@@ -16,15 +24,16 @@
|
|
|
16
24
|
"prepublishOnly": "tsc"
|
|
17
25
|
},
|
|
18
26
|
"files": [
|
|
19
|
-
"dist"
|
|
27
|
+
"dist",
|
|
28
|
+
"!dist/testing.*"
|
|
20
29
|
],
|
|
21
30
|
"engines": {
|
|
22
|
-
"node": ">=
|
|
31
|
+
"node": ">=20"
|
|
23
32
|
},
|
|
24
33
|
"repository": {
|
|
25
34
|
"type": "git",
|
|
26
35
|
"url": "https://github.com/poe-platform/poe-code.git",
|
|
27
|
-
"directory": "packages/tiny-mcp-server"
|
|
36
|
+
"directory": "packages/tiny-stdio-mcp-server"
|
|
28
37
|
},
|
|
29
38
|
"license": "MIT",
|
|
30
39
|
"keywords": [
|
package/dist/testing.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
-
import type { Server } from "./server.js";
|
|
3
|
-
export interface TestPair {
|
|
4
|
-
client: Client;
|
|
5
|
-
cleanup: () => Promise<void>;
|
|
6
|
-
}
|
|
7
|
-
export declare function createTestPair(server: Server): Promise<TestPair>;
|
package/dist/testing.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
-
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
3
|
-
export async function createTestPair(server) {
|
|
4
|
-
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
5
|
-
const client = new Client({
|
|
6
|
-
name: "test-client",
|
|
7
|
-
version: "1.0.0",
|
|
8
|
-
});
|
|
9
|
-
// Start server connection (runs in background)
|
|
10
|
-
const serverPromise = server.connectSDK(serverTransport);
|
|
11
|
-
// Connect client
|
|
12
|
-
await client.connect(clientTransport);
|
|
13
|
-
const cleanup = async () => {
|
|
14
|
-
await client.close();
|
|
15
|
-
await clientTransport.close();
|
|
16
|
-
await serverTransport.close();
|
|
17
|
-
await serverPromise;
|
|
18
|
-
};
|
|
19
|
-
return { client, cleanup };
|
|
20
|
-
}
|