typespec-http-mcp 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/lib.d.ts +3 -0
- package/dist/src/lib.js +17 -0
- package/dist/src/refusals.d.ts +3 -0
- package/dist/src/refusals.js +29 -1
- package/package.json +3 -3
package/dist/src/lib.d.ts
CHANGED
|
@@ -75,6 +75,9 @@ type Diagnostics = {
|
|
|
75
75
|
"tool-name-collision": {
|
|
76
76
|
readonly default: CallableMessage<["first", "second", "name"]>;
|
|
77
77
|
};
|
|
78
|
+
"shared-input-key": {
|
|
79
|
+
readonly default: CallableMessage<["operationId", "types"]>;
|
|
80
|
+
};
|
|
78
81
|
"binary-tool-input": {
|
|
79
82
|
readonly default: CallableMessage<["operationId", "types"]>;
|
|
80
83
|
};
|
package/dist/src/lib.js
CHANGED
|
@@ -128,6 +128,23 @@ const diagnostics = {
|
|
|
128
128
|
* contract no reader of the document could predict, and would put a whole upload through a model's
|
|
129
129
|
* context window.
|
|
130
130
|
*/
|
|
131
|
+
/**
|
|
132
|
+
* **An operation two of whose inputs would arrive as one argument is not a tool.**
|
|
133
|
+
*
|
|
134
|
+
* A tool's arguments are the path, query, header and cookie groups spread into one object, the
|
|
135
|
+
* body merged or named beside them - the same input a server's handler receives. `@header("x")`
|
|
136
|
+
* beside `@query("x")` therefore published one `x` argument, the later group's schema replacing
|
|
137
|
+
* the earlier, and the handler was handed one value for two declarations (typespec-http-graphql,
|
|
138
|
+
* 2026-10-16). `typespec-http-zod` names the pair in `EmittedRoute.sharedInputKeys` and reports it
|
|
139
|
+
* as its own `shared-input-key`; this is the tool surface declining it, as `typespec-hono` declines
|
|
140
|
+
* to mount it.
|
|
141
|
+
*/
|
|
142
|
+
"shared-input-key": {
|
|
143
|
+
severity: "warning",
|
|
144
|
+
messages: {
|
|
145
|
+
default: paramMessage `'${"operationId"}' is not a tool: ${"types"} would arrive as one argument, which holds one value. Give one of them a different name, or exclude the operation with 'exclude-tags'.`,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
131
148
|
"binary-tool-input": {
|
|
132
149
|
severity: "warning",
|
|
133
150
|
messages: {
|
package/dist/src/refusals.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { type Program } from "@typespec/compiler";
|
|
|
2
2
|
import type { HttpOperation } from "@typespec/http";
|
|
3
3
|
import type { EmittedRoute, RouteSchemaNames } from "typespec-http-zod";
|
|
4
4
|
export type Refusal = {
|
|
5
|
+
readonly kind: "shared-input-key";
|
|
6
|
+
readonly types: string;
|
|
7
|
+
} | {
|
|
5
8
|
readonly kind: "binary-tool-input";
|
|
6
9
|
readonly types: string;
|
|
7
10
|
} | {
|
package/dist/src/refusals.js
CHANGED
|
@@ -8,6 +8,14 @@ import { unvalidatedResponsesOf } from "./bodies.js";
|
|
|
8
8
|
* arithmetically impossible. A WARNING leaves the tool in place and says something about its quality.
|
|
9
9
|
* Conflating them would let a quality complaint quietly delete a tool.
|
|
10
10
|
*/
|
|
11
|
+
/** How a `shared-input-key` refusal names where each of the two inputs comes from. */
|
|
12
|
+
const INPUT_LOCATION_NOUNS = {
|
|
13
|
+
path: "path parameter",
|
|
14
|
+
query: "query parameter",
|
|
15
|
+
header: "header",
|
|
16
|
+
cookie: "cookie",
|
|
17
|
+
body: "body",
|
|
18
|
+
};
|
|
11
19
|
/** A media type a tool can actually send. `application/json`, and the `+json` structured suffix. */
|
|
12
20
|
function isJson(contentType) {
|
|
13
21
|
const type = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
@@ -70,6 +78,21 @@ function isMergeableBody(program, type) {
|
|
|
70
78
|
*/
|
|
71
79
|
export function refusalFor(program, route, operation) {
|
|
72
80
|
const types = route.requestContentTypes;
|
|
81
|
+
/**
|
|
82
|
+
* **Two inputs under one key cannot both be arguments.** A tool's arguments are the parameter
|
|
83
|
+
* groups spread into one object, as a server's handler input is, so `@header("x")` beside
|
|
84
|
+
* `@query("x")` published one `x` whose later schema replaced the earlier, and the handler was
|
|
85
|
+
* handed one value for two declarations. The library names every such pair; the operation is not
|
|
86
|
+
* a tool, for the reason `typespec-hono` does not mount it.
|
|
87
|
+
*/
|
|
88
|
+
if (route.sharedInputKeys.length > 0) {
|
|
89
|
+
return {
|
|
90
|
+
kind: "shared-input-key",
|
|
91
|
+
types: route.sharedInputKeys
|
|
92
|
+
.map((shared) => `the ${INPUT_LOCATION_NOUNS[shared.first]} '${shared.key}' and the ${INPUT_LOCATION_NOUNS[shared.second]} '${shared.key}'`)
|
|
93
|
+
.join("; "),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
73
96
|
/**
|
|
74
97
|
* A raw body is bytes or a stream; a multipart body is parts, one of which is usually a file.
|
|
75
98
|
* Neither is a JSON value, and encoding one into a string argument would put an upload through a
|
|
@@ -101,7 +124,12 @@ export function refusalFor(program, route, operation) {
|
|
|
101
124
|
* body is merged into the argument object, so it must have properties to merge.
|
|
102
125
|
*/
|
|
103
126
|
if (route.bodyProperty === undefined) {
|
|
104
|
-
|
|
127
|
+
/**
|
|
128
|
+
* **A body declared `void` or `never` is no body**, and the library lists no media type for
|
|
129
|
+
* one; read that way, there is nothing to merge. Read off the operation, its intrinsic type is
|
|
130
|
+
* not an object and the tool was refused as `non-object-body`.
|
|
131
|
+
*/
|
|
132
|
+
const body = types.length === 0 ? undefined : operation.parameters.body?.type;
|
|
105
133
|
if (!isMergeableBody(program, body)) {
|
|
106
134
|
return { kind: "non-object-body", types: body?.kind ?? "unknown" };
|
|
107
135
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typespec-http-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "TypeSpec emitter: generate an MCP tool surface, and the Zod validators it publishes, from an HTTP service definition, dispatching into the same handlers a generated HTTP server calls.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"provenance": true
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"typespec-http-zod": "^0.
|
|
48
|
+
"typespec-http-zod": "^0.30.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@hono/zod-validator": "^0.9.1",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"oxfmt": "^0.67.0",
|
|
68
68
|
"oxlint": "^1.82.0",
|
|
69
69
|
"typescript": "~7.0.2",
|
|
70
|
-
"typespec-hono": "0.
|
|
70
|
+
"typespec-hono": "0.27.0",
|
|
71
71
|
"typespec-http-mcp": "link:.",
|
|
72
72
|
"vitest": "^5.0.0",
|
|
73
73
|
"wrangler": "^4.131.1",
|