toolcraft 0.0.409 → 0.0.411
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/composition.json +3 -3
- package/dist/composition.json +3 -3
- package/node_modules/tiny-http-mcp-server/README.md +51 -0
- package/node_modules/tiny-http-mcp-server/dist/composition.json +11 -1
- package/node_modules/tiny-http-mcp-server/dist/fetch-body.d.ts +6 -0
- package/node_modules/tiny-http-mcp-server/dist/fetch-body.js +47 -0
- package/node_modules/tiny-http-mcp-server/dist/fetch.d.ts +23 -0
- package/node_modules/tiny-http-mcp-server/dist/fetch.js +130 -0
- package/node_modules/tiny-http-mcp-server/dist/modern-headers.js +1 -2
- package/node_modules/tiny-http-mcp-server/package.json +5 -1
- package/node_modules/tiny-stdio-mcp-server/README.md +11 -0
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/tiny-stdio-mcp-server/dist/core.d.ts +8 -0
- package/node_modules/tiny-stdio-mcp-server/dist/core.js +4 -0
- package/node_modules/tiny-stdio-mcp-server/dist/protocol-server.d.ts +48 -0
- package/node_modules/tiny-stdio-mcp-server/dist/protocol-server.js +1156 -0
- package/node_modules/tiny-stdio-mcp-server/dist/server.d.ts +3 -39
- package/node_modules/tiny-stdio-mcp-server/dist/server.js +4 -1144
- package/node_modules/tiny-stdio-mcp-server/dist/types.d.ts +2 -0
- package/node_modules/tiny-stdio-mcp-server/package.json +4 -0
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +2 -2
package/composition.json
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "tiny-http-mcp-server",
|
|
101
|
-
"version": "0.1.
|
|
101
|
+
"version": "0.1.89",
|
|
102
102
|
"license": "MIT"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "toolcraft",
|
|
116
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.411",
|
|
117
117
|
"license": "MIT"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
"name": "toolcraft-schema",
|
|
126
|
-
"version": "0.0.
|
|
126
|
+
"version": "0.0.411",
|
|
127
127
|
"license": "MIT"
|
|
128
128
|
},
|
|
129
129
|
{
|
package/dist/composition.json
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "tiny-http-mcp-server",
|
|
101
|
-
"version": "0.1.
|
|
101
|
+
"version": "0.1.89",
|
|
102
102
|
"license": "MIT"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "toolcraft",
|
|
116
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.411",
|
|
117
117
|
"license": "MIT"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
"name": "toolcraft-schema",
|
|
126
|
-
"version": "0.0.
|
|
126
|
+
"version": "0.0.411",
|
|
127
127
|
"license": "MIT"
|
|
128
128
|
},
|
|
129
129
|
{
|
|
@@ -389,6 +389,57 @@ CLI equivalent:
|
|
|
389
389
|
npx tiny-http-mcp-server --stateless
|
|
390
390
|
```
|
|
391
391
|
|
|
392
|
+
## Cloudflare Workers and Fetch hosts
|
|
393
|
+
|
|
394
|
+
Use the additive `tiny-http-mcp-server/fetch` entry point for a stateless
|
|
395
|
+
`Request` → `Response` handler. It shares the typed tool registry and protocol
|
|
396
|
+
engine with the Node server, without importing Node HTTP, stdio, or OAuth
|
|
397
|
+
modules. Existing `createHttpServer` integrations are unchanged.
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
import { createFetchServer, defineSchema } from "tiny-http-mcp-server/fetch";
|
|
401
|
+
|
|
402
|
+
const mcp = createFetchServer<{ userId: string }>({
|
|
403
|
+
name: "images",
|
|
404
|
+
version: "1.0.0",
|
|
405
|
+
maxRequestBytes: 128 * 1024,
|
|
406
|
+
maxResponseBytes: 512 * 1024,
|
|
407
|
+
maxConcurrentToolCalls: 4,
|
|
408
|
+
maxQueuedToolCalls: 0
|
|
409
|
+
}).tool("whoami", "Identify the caller", defineSchema({}), (_, { context }) =>
|
|
410
|
+
context.userId
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
export default {
|
|
414
|
+
async fetch(request: Request, env: Env) {
|
|
415
|
+
// Verify the key with your existing authentication system on EVERY request.
|
|
416
|
+
const user = await authenticateApiKey(request, env);
|
|
417
|
+
if (!user) return new Response("Unauthorized", { status: 401 });
|
|
418
|
+
return mcp.fetch(request, { userId: user.id });
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Authentication and URL routing belong to your host. The second `fetch` argument
|
|
424
|
+
is trusted local state; JSON-RPC parameters and `_meta` cannot override it.
|
|
425
|
+
Tool handlers also receive `request` and a cancellation `signal`. Use that signal
|
|
426
|
+
for downstream work; aborted requests must not keep consuming resources.
|
|
427
|
+
|
|
428
|
+
The Fetch transport returns JSON for POST, acknowledges notifications with 202,
|
|
429
|
+
and returns 405 with `Allow: POST` for GET/DELETE and other methods. It creates no
|
|
430
|
+
sessions and rejects batch requests before executing any member. Clients must
|
|
431
|
+
send `Content-Type: application/json` and accept both `application/json` and
|
|
432
|
+
`text/event-stream`. Origins are rejected unless explicitly listed in
|
|
433
|
+
`allowedOrigins`; the host owns CORS preflight/response headers. Thrown handler
|
|
434
|
+
exceptions are sanitized; return an explicit MCP `isError` result for an error
|
|
435
|
+
message intended for callers.
|
|
436
|
+
|
|
437
|
+
`.tool(...)` and `.registerTool(...)` support the same typed schemas, structured
|
|
438
|
+
outputs, and content results as the Node API. Request and response byte limits
|
|
439
|
+
default to 1 MiB. Tool concurrency, queue bounds, active request limits, and tool
|
|
440
|
+
timeouts use the shared server options. Stateless Fetch does not support
|
|
441
|
+
subscriptions or server-initiated notification streams.
|
|
442
|
+
|
|
392
443
|
## API Reference
|
|
393
444
|
|
|
394
445
|
The package re-exports the base server helpers from `tiny-stdio-mcp-server`, so you can import `defineSchema`, `createServer`, `Image`, `Audio`, `File`, and related types from here as well.
|
|
@@ -18,13 +18,23 @@
|
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"name": "tiny-http-mcp-server",
|
|
21
|
-
"version": "0.1.
|
|
21
|
+
"version": "0.1.89",
|
|
22
22
|
"license": "MIT"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"name": "tiny-mcp-client",
|
|
26
26
|
"version": "0.1.0",
|
|
27
27
|
"license": "MIT"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "tiny-stdio-mcp-server",
|
|
31
|
+
"version": "0.1.27",
|
|
32
|
+
"license": "MIT"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "toolcraft-schema",
|
|
36
|
+
"version": "0.0.1",
|
|
37
|
+
"license": "MIT"
|
|
28
38
|
}
|
|
29
39
|
]
|
|
30
40
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare class FetchBodyError extends Error {
|
|
2
|
+
readonly status: 400 | 413;
|
|
3
|
+
constructor(status: 400 | 413, message: string);
|
|
4
|
+
}
|
|
5
|
+
/** Bound bytes while reading, including bodies without Content-Length. */
|
|
6
|
+
export declare function readFetchBody(request: Request, maxBytes: number): Promise<string>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export class FetchBodyError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
constructor(status, message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.status = status;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Bound bytes while reading, including bodies without Content-Length. */
|
|
9
|
+
export async function readFetchBody(request, maxBytes) {
|
|
10
|
+
const length = request.headers.get("content-length");
|
|
11
|
+
if (length !== null && Number(length) > maxBytes) {
|
|
12
|
+
await request.body?.cancel();
|
|
13
|
+
throw new FetchBodyError(413, "Payload too large");
|
|
14
|
+
}
|
|
15
|
+
if (request.body === null)
|
|
16
|
+
return "";
|
|
17
|
+
const reader = request.body.getReader();
|
|
18
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
19
|
+
const abort = () => { void reader.cancel().catch(() => undefined); };
|
|
20
|
+
request.signal.addEventListener("abort", abort, { once: true });
|
|
21
|
+
let bytes = 0;
|
|
22
|
+
let text = "";
|
|
23
|
+
try {
|
|
24
|
+
request.signal.throwIfAborted();
|
|
25
|
+
while (true) {
|
|
26
|
+
const chunk = await reader.read();
|
|
27
|
+
request.signal.throwIfAborted();
|
|
28
|
+
if (chunk.done)
|
|
29
|
+
break;
|
|
30
|
+
bytes += chunk.value.byteLength;
|
|
31
|
+
if (bytes > maxBytes)
|
|
32
|
+
throw new FetchBodyError(413, "Payload too large");
|
|
33
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
34
|
+
}
|
|
35
|
+
return text + decoder.decode();
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
await reader.cancel().catch(() => undefined);
|
|
39
|
+
if (error instanceof FetchBodyError || request.signal.aborted)
|
|
40
|
+
throw error;
|
|
41
|
+
throw new FetchBodyError(400, "Invalid request body");
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
request.signal.removeEventListener("abort", abort);
|
|
45
|
+
reader.releaseLock();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type CallToolResult, type HandlerRequestContext, type InputRequiredResult, type ServerOptions, type ToolDefinition, type ToolReturn, type TypedSchema, type TypedOutputSchema } from "tiny-stdio-mcp-server/core";
|
|
2
|
+
export { defineSchema, ToolError } from "tiny-stdio-mcp-server/core";
|
|
3
|
+
export type { CallToolResult, TypedSchema, TypedOutputSchema } from "tiny-stdio-mcp-server/core";
|
|
4
|
+
export interface FetchServerOptions extends ServerOptions {
|
|
5
|
+
/** Defaults to 1 MiB. Enforced while reading the stream. */
|
|
6
|
+
maxRequestBytes?: number;
|
|
7
|
+
/** Defaults to 1 MiB. */
|
|
8
|
+
maxResponseBytes?: number;
|
|
9
|
+
/** Browser origins allowed to call this endpoint; absent rejects all Origin headers. */
|
|
10
|
+
allowedOrigins?: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
export interface FetchToolContext<TContext> extends HandlerRequestContext {
|
|
13
|
+
readonly request: Request;
|
|
14
|
+
readonly context: TContext;
|
|
15
|
+
}
|
|
16
|
+
export type FetchToolHandler<TIn, TContext, TOut = ToolReturn> = (input: TIn, context: FetchToolContext<TContext>) => TOut | CallToolResult | InputRequiredResult | Promise<TOut | CallToolResult | InputRequiredResult>;
|
|
17
|
+
export interface FetchServer<TContext = undefined> {
|
|
18
|
+
tool<TIn, TOut = never>(name: string, description: string, schema: TypedSchema<TIn>, handler: FetchToolHandler<TIn, TContext, TOut>, outputSchema?: TypedOutputSchema<TOut>): FetchServer<TContext>;
|
|
19
|
+
registerTool<TIn, TOut = never>(definition: Omit<ToolDefinition<TIn, TOut>, "handler">, handler: FetchToolHandler<TIn, TContext, TOut>): FetchServer<TContext>;
|
|
20
|
+
fetch(request: Request, ...context: undefined extends TContext ? [context?: TContext] : [context: TContext]): Promise<Response>;
|
|
21
|
+
}
|
|
22
|
+
/** Stateless Streamable HTTP. Authentication must run in the host before fetch(). */
|
|
23
|
+
export declare function createFetchServer<TContext = undefined>(options: FetchServerOptions): FetchServer<TContext>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createProtocolServer, ToolError } from "tiny-stdio-mcp-server/core";
|
|
2
|
+
import { parseMessage } from "tiny-stdio-mcp-server/jsonrpc";
|
|
3
|
+
import { MODERN_PROTOCOL_VERSION } from "tiny-stdio-mcp-server/protocol";
|
|
4
|
+
import { FetchBodyError, readFetchBody } from "./fetch-body.js";
|
|
5
|
+
import { validateModernHeaders } from "./modern-headers.js";
|
|
6
|
+
export { defineSchema, ToolError } from "tiny-stdio-mcp-server/core";
|
|
7
|
+
const versions = new Set(["2025-03-26", "2025-06-18", "2025-11-25", MODERN_PROTOCOL_VERSION]);
|
|
8
|
+
const unsupportedMethods = new Set(["resources/subscribe", "resources/unsubscribe", "subscriptions/listen"]);
|
|
9
|
+
function json(value, status = 200) {
|
|
10
|
+
return Response.json(value, { status, headers: { "cache-control": "no-store", "x-content-type-options": "nosniff" } });
|
|
11
|
+
}
|
|
12
|
+
function failure(code, message, status = 400, id = null) {
|
|
13
|
+
return json({ jsonrpc: "2.0", id, error: { code, message } }, status);
|
|
14
|
+
}
|
|
15
|
+
function validateRequest(request, options) {
|
|
16
|
+
const origin = request.headers.get("origin");
|
|
17
|
+
if (origin !== null && !options.allowedOrigins?.includes(origin))
|
|
18
|
+
return failure(-32600, "Origin not allowed", 403);
|
|
19
|
+
if (request.method !== "POST") {
|
|
20
|
+
const response = failure(-32600, "Method not allowed", 405);
|
|
21
|
+
response.headers.set("allow", "POST");
|
|
22
|
+
return response;
|
|
23
|
+
}
|
|
24
|
+
if (request.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "application/json")
|
|
25
|
+
return failure(-32600, "Content-Type must be application/json", 415);
|
|
26
|
+
const accepted = request.headers.get("accept")?.split(",").map(value => value.split(";")[0]?.trim().toLowerCase());
|
|
27
|
+
if (!accepted?.includes("application/json") || !accepted.includes("text/event-stream"))
|
|
28
|
+
return failure(-32600, "Accept must include application/json and text/event-stream", 406);
|
|
29
|
+
const version = request.headers.get("mcp-protocol-version");
|
|
30
|
+
if (version !== null && !versions.has(version))
|
|
31
|
+
return failure(-32600, "Unsupported protocol version");
|
|
32
|
+
if (request.headers.has("mcp-session-id"))
|
|
33
|
+
return failure(-32600, "This endpoint is stateless", 400);
|
|
34
|
+
}
|
|
35
|
+
/** Stateless Streamable HTTP. Authentication must run in the host before fetch(). */
|
|
36
|
+
export function createFetchServer(options) {
|
|
37
|
+
const maxRequestBytes = options.maxRequestBytes ?? 1024 * 1024;
|
|
38
|
+
const maxResponseBytes = options.maxResponseBytes ?? 1024 * 1024;
|
|
39
|
+
for (const bound of [maxRequestBytes, maxResponseBytes]) {
|
|
40
|
+
if (!Number.isSafeInteger(bound) || bound < 1)
|
|
41
|
+
throw new Error("Fetch byte limits must be positive safe integers");
|
|
42
|
+
}
|
|
43
|
+
const protocol = createProtocolServer({ ...options, supportNotifications: false, supportResourceSubscriptions: false });
|
|
44
|
+
function wrap(handler) {
|
|
45
|
+
return async (input, context) => {
|
|
46
|
+
const local = context.localContext;
|
|
47
|
+
try {
|
|
48
|
+
return await handler(input, { ...context, ...local });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Tool-authored error results are public; thrown exceptions may contain credentials.
|
|
52
|
+
throw new ToolError(-32603, "Tool execution failed");
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const server = {
|
|
57
|
+
tool(name, description, schema, handler, outputSchema) {
|
|
58
|
+
protocol.tool(name, description, schema, wrap(handler), outputSchema);
|
|
59
|
+
return server;
|
|
60
|
+
},
|
|
61
|
+
registerTool(definition, handler) {
|
|
62
|
+
protocol.registerTool(definition, wrap(handler));
|
|
63
|
+
return server;
|
|
64
|
+
},
|
|
65
|
+
async fetch(request, ...[context]) {
|
|
66
|
+
const invalid = validateRequest(request, options);
|
|
67
|
+
if (invalid !== undefined)
|
|
68
|
+
return invalid;
|
|
69
|
+
let raw;
|
|
70
|
+
try {
|
|
71
|
+
raw = await readFetchBody(request, maxRequestBytes);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (request.signal.aborted)
|
|
75
|
+
throw error;
|
|
76
|
+
return failure(-32600, error instanceof FetchBodyError ? error.message : "Invalid request body", error instanceof FetchBodyError ? error.status : 400);
|
|
77
|
+
}
|
|
78
|
+
// MCP 2025-06-18 and later prohibit batches. Reject before any side effects.
|
|
79
|
+
const parsed = parseMessage(raw);
|
|
80
|
+
if (!parsed.success)
|
|
81
|
+
return failure(parsed.error.code, parsed.error.message, 400, parsed.id);
|
|
82
|
+
if (parsed.isNotification)
|
|
83
|
+
return new Response(null, { status: 202 });
|
|
84
|
+
const message = parsed.request;
|
|
85
|
+
if (!("id" in message))
|
|
86
|
+
return failure(-32600, "Invalid Request");
|
|
87
|
+
if (message.method.startsWith("notifications/"))
|
|
88
|
+
return failure(-32600, "Invalid Request", 400, message.id);
|
|
89
|
+
if (unsupportedMethods.has(message.method))
|
|
90
|
+
return failure(-32601, "Method not found", 200, message.id);
|
|
91
|
+
const headers = Object.fromEntries(request.headers);
|
|
92
|
+
const metadata = message.params?._meta;
|
|
93
|
+
const modern = request.headers.get("mcp-protocol-version") === MODERN_PROTOCOL_VERSION ||
|
|
94
|
+
metadata?.["io.modelcontextprotocol/protocolVersion"] === MODERN_PROTOCOL_VERSION;
|
|
95
|
+
if (modern) {
|
|
96
|
+
const error = validateModernHeaders(headers, message);
|
|
97
|
+
if (error !== undefined)
|
|
98
|
+
return json({ jsonrpc: "2.0", id: message.id, error }, 400);
|
|
99
|
+
}
|
|
100
|
+
// Fresh lifecycle per request isolates duplicate IDs and cancellation across callers.
|
|
101
|
+
const session = protocol.createMessageSession();
|
|
102
|
+
try {
|
|
103
|
+
if (!modern && message.method !== "initialize") {
|
|
104
|
+
await session.handleMessage("initialize", { protocolVersion: request.headers.get("mcp-protocol-version") ?? "2025-03-26" });
|
|
105
|
+
}
|
|
106
|
+
const handled = await session.handleMessage(message.method, message.params, {
|
|
107
|
+
...(message.id !== null ? { requestId: message.id } : {}),
|
|
108
|
+
signal: request.signal,
|
|
109
|
+
parameterHeaders: headers,
|
|
110
|
+
localContext: { request, context }
|
|
111
|
+
});
|
|
112
|
+
request.signal.throwIfAborted();
|
|
113
|
+
const response = { jsonrpc: "2.0", id: message.id, ...handled };
|
|
114
|
+
const body = JSON.stringify(response);
|
|
115
|
+
if (new TextEncoder().encode(body).byteLength > maxResponseBytes)
|
|
116
|
+
return failure(-32603, "Response exceeds byte limit", 200, message.id);
|
|
117
|
+
return json(response);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (request.signal.aborted)
|
|
121
|
+
throw error;
|
|
122
|
+
return failure(-32603, "Internal error", 200, message.id);
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
session.close();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
return server;
|
|
130
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { JSON_RPC_ERROR_CODES } from "tiny-stdio-mcp-server";
|
|
2
1
|
import { decodeHeaderValue } from "tiny-stdio-mcp-server/headers";
|
|
3
2
|
export function validateModernHeaders(headers, request) {
|
|
4
3
|
const metadata = request.params?._meta;
|
|
@@ -7,7 +6,7 @@ export function validateModernHeaders(headers, request) {
|
|
|
7
6
|
: undefined;
|
|
8
7
|
if (typeof version !== "string")
|
|
9
8
|
return {
|
|
10
|
-
code:
|
|
9
|
+
code: -32602,
|
|
11
10
|
message: "Missing protocol version request metadata"
|
|
12
11
|
};
|
|
13
12
|
const expected = { "mcp-protocol-version": version };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-http-mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.89",
|
|
4
4
|
"description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
"./test-support": {
|
|
25
25
|
"types": "./dist/test-support.d.ts",
|
|
26
26
|
"import": "./dist/test-support.js"
|
|
27
|
+
},
|
|
28
|
+
"./fetch": {
|
|
29
|
+
"types": "./dist/fetch.d.ts",
|
|
30
|
+
"import": "./dist/fetch.js"
|
|
27
31
|
}
|
|
28
32
|
},
|
|
29
33
|
"scripts": {
|
|
@@ -245,3 +245,14 @@ per-tool schemas, and per-call content helper options such as `maxBytes` for rem
|
|
|
245
245
|
## License
|
|
246
246
|
|
|
247
247
|
MIT
|
|
248
|
+
|
|
249
|
+
## Protocol-only hosts
|
|
250
|
+
|
|
251
|
+
Import `createProtocolServer` and `defineSchema` from
|
|
252
|
+
`tiny-stdio-mcp-server/core` when your host supplies its own transport. This
|
|
253
|
+
entry point loads no Node stdio modules. Use `createMessageSession()` for an
|
|
254
|
+
isolated request lifecycle and close it when the transport completes. The
|
|
255
|
+
`handleMessage` context accepts `localContext` for host-owned state; tool
|
|
256
|
+
handlers receive it separately from client parameters and metadata. Use the
|
|
257
|
+
ordinary root `createServer` export for `listen()` or `connect()`; the core
|
|
258
|
+
entry point does not provide a stdio runtime.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Protocol engine and typed tools without Node transport imports. */
|
|
2
|
+
export { createProtocolServer } from "./protocol-server.js";
|
|
3
|
+
export type { Server, MessageRequestContext, MessageSession } from "./protocol-server.js";
|
|
4
|
+
export { defineSchema } from "./schema.js";
|
|
5
|
+
export type { TypedSchema, TypedOutputSchema } from "./schema.js";
|
|
6
|
+
export { ToolError } from "./types.js";
|
|
7
|
+
export type { CallToolResult, HandlerRequestContext, InputRequiredResult, ServerOptions, ToolDefinition } from "./types.js";
|
|
8
|
+
export type { ToolReturn } from "./content/convert.js";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ServerOptions, ToolDefinition, ToolHandler, HandleResult, Prompt, PromptHandler, Resource, ResourceHandler, ResourceTemplate, Transport, SDKTransport, JSONRPCNotification } from "./types.js";
|
|
2
|
+
import type { TypedSchema, TypedOutputSchema } from "./schema.js";
|
|
3
|
+
interface StdioRuntime {
|
|
4
|
+
readline: typeof import("node:readline");
|
|
5
|
+
StdioInput: typeof import("./stdio-input.js").StdioInput;
|
|
6
|
+
StdioOutput: typeof import("./stdio-output.js").StdioOutput;
|
|
7
|
+
}
|
|
8
|
+
export interface Server {
|
|
9
|
+
tool<TIn, TOut = never>(name: string, description: string, inputSchema: TypedSchema<TIn>, handler: ToolHandler<TIn, TOut>, outputSchema?: TypedOutputSchema<TOut>): Server;
|
|
10
|
+
registerTool<TIn, TOut = never>(definition: Omit<ToolDefinition<TIn, TOut>, "handler">, handler: ToolHandler<TIn, TOut>): Server;
|
|
11
|
+
prompt(definition: Prompt, handler: PromptHandler): Server;
|
|
12
|
+
resource(definition: Resource, handler: ResourceHandler): Server;
|
|
13
|
+
resourceTemplate(definition: ResourceTemplate, handler: ResourceHandler): Server;
|
|
14
|
+
method(name: string, handler: CustomMethodHandler): Server;
|
|
15
|
+
onNotification(listener: (notification: JSONRPCNotification) => void): () => void;
|
|
16
|
+
removeTool(name: string): boolean;
|
|
17
|
+
removePrompt(name: string): boolean;
|
|
18
|
+
removeResource(uri: string): boolean;
|
|
19
|
+
removeResourceTemplate(uriTemplate: string): boolean;
|
|
20
|
+
notifyToolsChanged(): Promise<void>;
|
|
21
|
+
notifyPromptsChanged(): Promise<void>;
|
|
22
|
+
notifyResourcesChanged(): Promise<void>;
|
|
23
|
+
notifyResourceUpdated(uri: string): Promise<void>;
|
|
24
|
+
createMessageSession(listener?: (notification: JSONRPCNotification) => void | Promise<void>): MessageSession;
|
|
25
|
+
handleMessage(method: string, params?: Record<string, unknown>, context?: MessageRequestContext): Promise<HandleResult>;
|
|
26
|
+
listen(): Promise<void>;
|
|
27
|
+
connect(transport: Transport): Promise<void>;
|
|
28
|
+
connectSDK(transport: SDKTransport): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export interface MessageSessionContext {
|
|
31
|
+
readonly signal: AbortSignal;
|
|
32
|
+
notify(method: string, params?: Record<string, unknown>): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export interface MessageRequestContext {
|
|
35
|
+
requestId?: string | number;
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
parameterHeaders?: Record<string, string | string[] | undefined>;
|
|
38
|
+
/** Host-only state, never read from JSON-RPC params or metadata. */
|
|
39
|
+
localContext?: unknown;
|
|
40
|
+
}
|
|
41
|
+
export type CustomMethodHandler = (params: Record<string, unknown> | undefined, session: MessageSessionContext) => unknown | Promise<unknown>;
|
|
42
|
+
export type MessageHandler = (method: string, params?: Record<string, unknown>, context?: MessageRequestContext) => Promise<HandleResult>;
|
|
43
|
+
export interface MessageSession {
|
|
44
|
+
handleMessage: MessageHandler;
|
|
45
|
+
close(): void;
|
|
46
|
+
}
|
|
47
|
+
export declare function createProtocolServer(options: ServerOptions, stdio?: StdioRuntime): Server;
|
|
48
|
+
export {};
|