@every-app/sdk 0.2.0 → 0.3.0-rc.10
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/LICENSE +21 -0
- package/README.md +609 -3
- package/dist/cloudflare/catalogSettings.generated.d.ts +81 -0
- package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
- package/dist/cloudflare/catalogSettings.generated.js +174 -0
- package/dist/cloudflare/index.d.ts +23 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +24 -0
- package/dist/cloudflare/sentinel.d.ts +127 -0
- package/dist/cloudflare/sentinel.d.ts.map +1 -0
- package/dist/cloudflare/sentinel.js +85 -0
- package/dist/cloudflare/worker.d.ts +805 -0
- package/dist/cloudflare/worker.d.ts.map +1 -0
- package/dist/cloudflare/worker.js +997 -0
- package/dist/dev/index.d.ts +8 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +7 -0
- package/dist/dev/keypair.d.ts +26 -0
- package/dist/dev/keypair.d.ts.map +1 -0
- package/dist/dev/keypair.js +62 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/internal/aiDefault.d.ts +204 -0
- package/dist/internal/aiDefault.d.ts.map +1 -0
- package/dist/internal/aiDefault.js +334 -0
- package/dist/internal/aiProviders.d.ts +72 -0
- package/dist/internal/aiProviders.d.ts.map +1 -0
- package/dist/internal/aiProviders.js +233 -0
- package/dist/internal/appSettings.d.ts +315 -0
- package/dist/internal/appSettings.d.ts.map +1 -0
- package/dist/internal/appSettings.js +549 -0
- package/dist/internal/audit.d.ts +108 -0
- package/dist/internal/audit.d.ts.map +1 -0
- package/dist/internal/audit.js +235 -0
- package/dist/internal/capabilities.d.ts +3174 -0
- package/dist/internal/capabilities.d.ts.map +1 -0
- package/dist/internal/capabilities.js +1110 -0
- package/dist/internal/catalog/commerce.d.ts +394 -0
- package/dist/internal/catalog/commerce.d.ts.map +1 -0
- package/dist/internal/catalog/commerce.js +477 -0
- package/dist/internal/catalog/comms.d.ts +375 -0
- package/dist/internal/catalog/comms.d.ts.map +1 -0
- package/dist/internal/catalog/comms.js +520 -0
- package/dist/internal/catalog/index.d.ts +1973 -0
- package/dist/internal/catalog/index.d.ts.map +1 -0
- package/dist/internal/catalog/index.js +19 -0
- package/dist/internal/catalog/inference.d.ts +393 -0
- package/dist/internal/catalog/inference.d.ts.map +1 -0
- package/dist/internal/catalog/inference.js +460 -0
- package/dist/internal/catalog/infra.d.ts +423 -0
- package/dist/internal/catalog/infra.d.ts.map +1 -0
- package/dist/internal/catalog/infra.js +543 -0
- package/dist/internal/catalog/search.d.ts +400 -0
- package/dist/internal/catalog/search.d.ts.map +1 -0
- package/dist/internal/catalog/search.js +463 -0
- package/dist/internal/devProviders.d.ts +49 -0
- package/dist/internal/devProviders.d.ts.map +1 -0
- package/dist/internal/devProviders.js +80 -0
- package/dist/internal/email.d.ts +280 -0
- package/dist/internal/email.d.ts.map +1 -0
- package/dist/internal/email.js +613 -0
- package/dist/internal/events.d.ts +193 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +367 -0
- package/dist/internal/gatewaySettings.d.ts +83 -0
- package/dist/internal/gatewaySettings.d.ts.map +1 -0
- package/dist/internal/gatewaySettings.js +215 -0
- package/dist/internal/identity.d.ts +57 -5
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +99 -22
- package/dist/internal/index.d.ts +22 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +22 -1
- package/dist/internal/members.d.ts +36 -0
- package/dist/internal/members.d.ts.map +1 -0
- package/dist/internal/members.js +7 -0
- package/dist/internal/oauthClient.d.ts +61 -0
- package/dist/internal/oauthClient.d.ts.map +1 -0
- package/dist/internal/oauthClient.js +133 -0
- package/dist/internal/oauthPresets.d.ts +33 -0
- package/dist/internal/oauthPresets.d.ts.map +1 -0
- package/dist/internal/oauthPresets.js +1064 -0
- package/dist/internal/oauthScopes.d.ts +172 -0
- package/dist/internal/oauthScopes.d.ts.map +1 -0
- package/dist/internal/oauthScopes.js +510 -0
- package/dist/internal/oauthSpec.d.ts +102 -0
- package/dist/internal/oauthSpec.d.ts.map +1 -0
- package/dist/internal/oauthSpec.js +789 -0
- package/dist/internal/organizationName.d.ts +18 -0
- package/dist/internal/organizationName.d.ts.map +1 -0
- package/dist/internal/organizationName.js +24 -0
- package/dist/internal/protocol.d.ts +150 -3
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +163 -2
- package/dist/internal/providerApps.d.ts +75 -0
- package/dist/internal/providerApps.d.ts.map +1 -0
- package/dist/internal/providerApps.js +59 -0
- package/dist/internal/providerRegistry.d.ts +218 -0
- package/dist/internal/providerRegistry.d.ts.map +1 -0
- package/dist/internal/providerRegistry.js +432 -0
- package/dist/internal/providerSpec.d.ts +66 -0
- package/dist/internal/providerSpec.d.ts.map +1 -0
- package/dist/internal/providerSpec.js +1154 -0
- package/dist/internal/remoteMcp.d.ts +188 -0
- package/dist/internal/remoteMcp.d.ts.map +1 -0
- package/dist/internal/remoteMcp.js +543 -0
- package/dist/internal/signInProviders.d.ts +104 -0
- package/dist/internal/signInProviders.d.ts.map +1 -0
- package/dist/internal/signInProviders.js +245 -0
- package/dist/internal/tools.d.ts +115 -0
- package/dist/internal/tools.d.ts.map +1 -0
- package/dist/internal/tools.js +80 -0
- package/dist/manifest.d.ts +238 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +30 -0
- package/dist/server/ai.d.ts +111 -0
- package/dist/server/ai.d.ts.map +1 -0
- package/dist/server/ai.js +145 -0
- package/dist/server/aiBinding.d.ts +68 -0
- package/dist/server/aiBinding.d.ts.map +1 -0
- package/dist/server/aiBinding.js +294 -0
- package/dist/server/attribution.d.ts +43 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +75 -0
- package/dist/server/authorizeUrl.d.ts +43 -0
- package/dist/server/authorizeUrl.d.ts.map +1 -0
- package/dist/server/authorizeUrl.js +106 -0
- package/dist/server/connectUrl.d.ts +21 -0
- package/dist/server/connectUrl.d.ts.map +1 -0
- package/dist/server/connectUrl.js +37 -0
- package/dist/server/context.d.ts +68 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +117 -0
- package/dist/server/emailBinding.d.ts +72 -0
- package/dist/server/emailBinding.d.ts.map +1 -0
- package/dist/server/emailBinding.js +124 -0
- package/dist/server/emit.d.ts +63 -0
- package/dist/server/emit.d.ts.map +1 -0
- package/dist/server/emit.js +101 -0
- package/dist/server/env.d.ts +44 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +1 -0
- package/dist/server/everyApp.d.ts +65 -19
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +195 -30
- package/dist/server/fromMcpTools.d.ts +89 -0
- package/dist/server/fromMcpTools.d.ts.map +1 -0
- package/dist/server/fromMcpTools.js +192 -0
- package/dist/server/gatewayFetch.d.ts +54 -14
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +201 -37
- package/dist/server/gatewayUrl.d.ts +13 -0
- package/dist/server/gatewayUrl.d.ts.map +1 -0
- package/dist/server/gatewayUrl.js +34 -0
- package/dist/server/index.d.ts +23 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +19 -2
- package/dist/server/integrationFetch.d.ts +162 -0
- package/dist/server/integrationFetch.d.ts.map +1 -0
- package/dist/server/integrationFetch.js +688 -0
- package/dist/server/listMembers.d.ts +32 -0
- package/dist/server/listMembers.d.ts.map +1 -0
- package/dist/server/listMembers.js +71 -0
- package/dist/server/nodeServer.d.ts +48 -0
- package/dist/server/nodeServer.d.ts.map +1 -0
- package/dist/server/nodeServer.js +45 -0
- package/dist/server/refusal.d.ts +55 -0
- package/dist/server/refusal.d.ts.map +1 -0
- package/dist/server/refusal.js +193 -0
- package/dist/server/sendEmail.d.ts +39 -0
- package/dist/server/sendEmail.d.ts.map +1 -0
- package/dist/server/sendEmail.js +114 -0
- package/dist/server/tools.d.ts +184 -0
- package/dist/server/tools.d.ts.map +1 -0
- package/dist/server/tools.js +347 -0
- package/dist/server/toolsEndpoint.d.ts +32 -0
- package/dist/server/toolsEndpoint.d.ts.map +1 -0
- package/dist/server/toolsEndpoint.js +237 -0
- package/dist/tanstack-start/index.d.ts +9 -0
- package/dist/tanstack-start/index.d.ts.map +1 -0
- package/dist/tanstack-start/index.js +29 -0
- package/dist/testing/index.d.ts +93 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +156 -0
- package/package.json +42 -8
- package/dist/server/mcp.d.ts +0 -66
- package/dist/server/mcp.d.ts.map +0 -1
- package/dist/server/mcp.js +0 -147
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `defineTools()` — agent tools an app offers to MCP clients through the
|
|
3
|
+
* Every App gateway.
|
|
4
|
+
*
|
|
5
|
+
* export const tools = defineTools(
|
|
6
|
+
* {
|
|
7
|
+
* list_todos: {
|
|
8
|
+
* description: "List the user's todos.",
|
|
9
|
+
* risk: "read",
|
|
10
|
+
* input: z.object({}).strict(),
|
|
11
|
+
* handler: async (_input, { user }) => listTodos(user.id),
|
|
12
|
+
* },
|
|
13
|
+
* },
|
|
14
|
+
* { instructions: "Never guess todo ids; call list_todos first." },
|
|
15
|
+
* );
|
|
16
|
+
* export default everyApp(handler, { tools });
|
|
17
|
+
*
|
|
18
|
+
* Apps never speak MCP. The gateway snapshots this catalog at deploy, serves
|
|
19
|
+
* MCP clients from the snapshot, and calls a tool over the internal tools
|
|
20
|
+
* contract (../internal/tools.ts) with a verified `chan: "mcp"` identity.
|
|
21
|
+
*
|
|
22
|
+
* `input` and `output` accept any validator implementing Standard Schema and
|
|
23
|
+
* Standard JSON Schema (zod >= 4.2 does both), or a plain
|
|
24
|
+
* `{ jsonSchema, validate }` pair. The SDK itself takes no dependency.
|
|
25
|
+
*/
|
|
26
|
+
import { type EveryAppUser, type ToolCallResultV1, type ToolDescriptorV1, type ToolIssueV1, type ToolRisk } from "../internal/index.js";
|
|
27
|
+
import type { ExecutionContextLike } from "./everyApp.js";
|
|
28
|
+
/** Reported with every catalog; must match package.json. */
|
|
29
|
+
export declare const SDK_VERSION = "0.3.0";
|
|
30
|
+
/**
|
|
31
|
+
* Throw from a tool handler to return an error the model can read and act on
|
|
32
|
+
* ("No todo with that id"). Any other error is logged here and reaches the
|
|
33
|
+
* client only as "Internal error in <app> (ref <call id>)".
|
|
34
|
+
*/
|
|
35
|
+
export declare class ToolError extends Error {
|
|
36
|
+
constructor(message: string);
|
|
37
|
+
}
|
|
38
|
+
type StandardPathSegment = PropertyKey | {
|
|
39
|
+
readonly key: PropertyKey;
|
|
40
|
+
};
|
|
41
|
+
interface StandardIssue {
|
|
42
|
+
readonly message: string;
|
|
43
|
+
readonly path?: ReadonlyArray<StandardPathSegment> | undefined;
|
|
44
|
+
}
|
|
45
|
+
type StandardResult<Output> = {
|
|
46
|
+
readonly value: Output;
|
|
47
|
+
readonly issues?: undefined;
|
|
48
|
+
} | {
|
|
49
|
+
readonly issues: ReadonlyArray<StandardIssue>;
|
|
50
|
+
};
|
|
51
|
+
interface StandardSchemaProps<Input, Output> {
|
|
52
|
+
readonly version: 1;
|
|
53
|
+
readonly vendor: string;
|
|
54
|
+
readonly validate: (value: unknown, options?: {
|
|
55
|
+
readonly libraryOptions?: Record<string, unknown>;
|
|
56
|
+
}) => StandardResult<Output> | Promise<StandardResult<Output>>;
|
|
57
|
+
readonly types?: {
|
|
58
|
+
readonly input: Input;
|
|
59
|
+
readonly output: Output;
|
|
60
|
+
} | undefined;
|
|
61
|
+
}
|
|
62
|
+
interface StandardJsonSchemaConverter {
|
|
63
|
+
readonly input: (options: {
|
|
64
|
+
readonly target: string;
|
|
65
|
+
}) => Record<string, unknown>;
|
|
66
|
+
readonly output: (options: {
|
|
67
|
+
readonly target: string;
|
|
68
|
+
}) => Record<string, unknown>;
|
|
69
|
+
}
|
|
70
|
+
/** A Standard Schema validator that also converts to JSON Schema (zod >= 4.2). */
|
|
71
|
+
export interface StandardSchemaWithJSON<Input = unknown, Output = Input> {
|
|
72
|
+
readonly "~standard": StandardSchemaProps<Input, Output> & {
|
|
73
|
+
readonly jsonSchema: StandardJsonSchemaConverter;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** For validators without Standard JSON Schema: supply the JSON Schema too. */
|
|
77
|
+
export interface PlainToolSchema<Output = unknown> {
|
|
78
|
+
jsonSchema: Record<string, unknown>;
|
|
79
|
+
validate(value: unknown): StandardResult<Output> | Promise<StandardResult<Output>>;
|
|
80
|
+
}
|
|
81
|
+
export type ToolSchema<Output = unknown> = StandardSchemaWithJSON<unknown, Output> | PlainToolSchema<Output>;
|
|
82
|
+
/** What a tool handler receives besides its validated input. */
|
|
83
|
+
export interface ToolContext<TEnv = Cloudflare.Env> {
|
|
84
|
+
/** The verified caller. `channel` is "mcp"; `toolCall` names this call. */
|
|
85
|
+
user: EveryAppUser;
|
|
86
|
+
env: TEnv;
|
|
87
|
+
ctx: ExecutionContextLike;
|
|
88
|
+
request: Request;
|
|
89
|
+
/** Unique id of this call; also the ref in masked error messages. */
|
|
90
|
+
callId: string;
|
|
91
|
+
}
|
|
92
|
+
export interface ToolDefinition<TInput = unknown> {
|
|
93
|
+
/** Short human-readable name clients may show. */
|
|
94
|
+
title?: string;
|
|
95
|
+
/** What the tool does and when to use it. The model reads this. */
|
|
96
|
+
description: string;
|
|
97
|
+
/**
|
|
98
|
+
* `read` changes nothing. `write` creates or changes data. `destructive`
|
|
99
|
+
* deletes or irreversibly changes data; AI clients can't see or call
|
|
100
|
+
* destructive tools until approvals exist.
|
|
101
|
+
*/
|
|
102
|
+
risk: ToolRisk;
|
|
103
|
+
/** Arguments schema; must describe an object. */
|
|
104
|
+
input: ToolSchema<TInput>;
|
|
105
|
+
/**
|
|
106
|
+
* Result schema; must describe an object. The result is validated and
|
|
107
|
+
* also sent as MCP structured content.
|
|
108
|
+
*/
|
|
109
|
+
output?: ToolSchema;
|
|
110
|
+
/** Repeating a call with the same arguments has no further effect. */
|
|
111
|
+
idempotent?: boolean;
|
|
112
|
+
/** The tool reaches systems outside this app (other APIs, the web). */
|
|
113
|
+
openWorld?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Return a string (sent as text), a JSON-serializable value (sent as a
|
|
116
|
+
* JSON text block), or {@link toolResult} for text and data together.
|
|
117
|
+
* Throw {@link ToolError} for errors the model may see.
|
|
118
|
+
*/
|
|
119
|
+
handler: (input: TInput, context: ToolContext) => unknown;
|
|
120
|
+
}
|
|
121
|
+
declare const TOOL_RESULT: unique symbol;
|
|
122
|
+
/** What {@link toolResult} returns; a handler returns it as is. */
|
|
123
|
+
export interface ToolResult {
|
|
124
|
+
readonly [TOOL_RESULT]: true;
|
|
125
|
+
readonly text: string;
|
|
126
|
+
readonly structured: Record<string, unknown>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Return a written result and the same result as data. The model reads
|
|
130
|
+
* `text` (a summary, a table); clients also get `structured`, checked
|
|
131
|
+
* against the tool's `output` schema. Without this, a tool with an `output`
|
|
132
|
+
* schema sends its value as JSON text.
|
|
133
|
+
*/
|
|
134
|
+
export declare function toolResult(result: {
|
|
135
|
+
text: string;
|
|
136
|
+
structured: Record<string, unknown>;
|
|
137
|
+
}): ToolResult;
|
|
138
|
+
export interface DefineToolsOptions {
|
|
139
|
+
/** Guidance for the model that spans this app's tools (at most 2 KB). */
|
|
140
|
+
instructions?: string;
|
|
141
|
+
}
|
|
142
|
+
/** Returned by {@link defineTools}; pass it to `everyApp(…, { tools })`. */
|
|
143
|
+
export interface ToolSet {
|
|
144
|
+
/** Tool names, sorted. */
|
|
145
|
+
readonly names: readonly string[];
|
|
146
|
+
}
|
|
147
|
+
export interface ToolCatalog {
|
|
148
|
+
instructions?: string;
|
|
149
|
+
tools: ToolDescriptorV1[];
|
|
150
|
+
hash: string;
|
|
151
|
+
/** Tools left out because they can't be described, and why. */
|
|
152
|
+
warnings: string[];
|
|
153
|
+
}
|
|
154
|
+
interface ToolSetInternals {
|
|
155
|
+
tool(name: string): ToolDefinition | undefined;
|
|
156
|
+
/** Descriptors and hash, computed once per isolate. */
|
|
157
|
+
catalog(): Promise<ToolCatalog>;
|
|
158
|
+
}
|
|
159
|
+
/** @internal The everyApp() side of a tool set. */
|
|
160
|
+
export declare function toolSetInternals(toolSet: ToolSet): ToolSetInternals;
|
|
161
|
+
/**
|
|
162
|
+
* Define an app's agent tools. Names are lowercase snake_case (at most 48
|
|
163
|
+
* characters); the gateway prefixes them with the app id where several apps
|
|
164
|
+
* share one MCP endpoint. Handler inputs are typed from each `input` schema.
|
|
165
|
+
*/
|
|
166
|
+
export declare function defineTools<TInputs extends Record<string, unknown>>(tools: {
|
|
167
|
+
[K in keyof TInputs]: ToolDefinition<TInputs[K]>;
|
|
168
|
+
}, options?: DefineToolsOptions): ToolSet;
|
|
169
|
+
export type ValidationOutcome<T> = {
|
|
170
|
+
ok: true;
|
|
171
|
+
value: T;
|
|
172
|
+
} | {
|
|
173
|
+
ok: false;
|
|
174
|
+
issues: ToolIssueV1[];
|
|
175
|
+
};
|
|
176
|
+
/** Run a tool schema's validator. */
|
|
177
|
+
export declare function validateWithSchema<T>(schema: ToolSchema<T>, value: unknown): Promise<ValidationOutcome<T>>;
|
|
178
|
+
/**
|
|
179
|
+
* Turn a handler's return value into a tool result. With an output schema,
|
|
180
|
+
* the value must validate and is sent as structured content as well as text.
|
|
181
|
+
*/
|
|
182
|
+
export declare function toToolResult(definition: ToolDefinition, value: unknown): Promise<ToolCallResultV1>;
|
|
183
|
+
export {};
|
|
184
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `defineTools()` — agent tools an app offers to MCP clients through the
|
|
3
|
+
* Every App gateway.
|
|
4
|
+
*
|
|
5
|
+
* export const tools = defineTools(
|
|
6
|
+
* {
|
|
7
|
+
* list_todos: {
|
|
8
|
+
* description: "List the user's todos.",
|
|
9
|
+
* risk: "read",
|
|
10
|
+
* input: z.object({}).strict(),
|
|
11
|
+
* handler: async (_input, { user }) => listTodos(user.id),
|
|
12
|
+
* },
|
|
13
|
+
* },
|
|
14
|
+
* { instructions: "Never guess todo ids; call list_todos first." },
|
|
15
|
+
* );
|
|
16
|
+
* export default everyApp(handler, { tools });
|
|
17
|
+
*
|
|
18
|
+
* Apps never speak MCP. The gateway snapshots this catalog at deploy, serves
|
|
19
|
+
* MCP clients from the snapshot, and calls a tool over the internal tools
|
|
20
|
+
* contract (../internal/tools.ts) with a verified `chan: "mcp"` identity.
|
|
21
|
+
*
|
|
22
|
+
* `input` and `output` accept any validator implementing Standard Schema and
|
|
23
|
+
* Standard JSON Schema (zod >= 4.2 does both), or a plain
|
|
24
|
+
* `{ jsonSchema, validate }` pair. The SDK itself takes no dependency.
|
|
25
|
+
*/
|
|
26
|
+
import { TOOL_NAME_PATTERN, catalogHash, isToolRisk, } from "../internal/index.js";
|
|
27
|
+
/** Reported with every catalog; must match package.json. */
|
|
28
|
+
export const SDK_VERSION = "0.3.0";
|
|
29
|
+
const JSON_SCHEMA_TARGET = "draft-2020-12";
|
|
30
|
+
const DRAFT_2020_12 = "https://json-schema.org/draft/2020-12/schema";
|
|
31
|
+
// The 2026-07-28 MCP revision lets a schema property ask clients to mirror an
|
|
32
|
+
// argument into an HTTP header. Apps never route on headers, and the gateway
|
|
33
|
+
// fronts many apps, so the hint is never passed on.
|
|
34
|
+
const MCP_HEADER_KEYWORD = "x-mcp-header";
|
|
35
|
+
/**
|
|
36
|
+
* Throw from a tool handler to return an error the model can read and act on
|
|
37
|
+
* ("No todo with that id"). Any other error is logged here and reaches the
|
|
38
|
+
* client only as "Internal error in <app> (ref <call id>)".
|
|
39
|
+
*/
|
|
40
|
+
export class ToolError extends Error {
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "ToolError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const TOOL_RESULT = Symbol.for("everyapp.toolResult");
|
|
47
|
+
/**
|
|
48
|
+
* Return a written result and the same result as data. The model reads
|
|
49
|
+
* `text` (a summary, a table); clients also get `structured`, checked
|
|
50
|
+
* against the tool's `output` schema. Without this, a tool with an `output`
|
|
51
|
+
* schema sends its value as JSON text.
|
|
52
|
+
*/
|
|
53
|
+
export function toolResult(result) {
|
|
54
|
+
return {
|
|
55
|
+
[TOOL_RESULT]: true,
|
|
56
|
+
text: result.text,
|
|
57
|
+
structured: result.structured,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function isToolResult(value) {
|
|
61
|
+
return (isRecord(value) && value[TOOL_RESULT] === true);
|
|
62
|
+
}
|
|
63
|
+
const internals = new WeakMap();
|
|
64
|
+
/** @internal The everyApp() side of a tool set. */
|
|
65
|
+
export function toolSetInternals(toolSet) {
|
|
66
|
+
const found = internals.get(toolSet);
|
|
67
|
+
if (!found) {
|
|
68
|
+
throw new TypeError("tools must be the value returned by defineTools()");
|
|
69
|
+
}
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Define an app's agent tools. Names are lowercase snake_case (at most 48
|
|
74
|
+
* characters); the gateway prefixes them with the app id where several apps
|
|
75
|
+
* share one MCP endpoint. Handler inputs are typed from each `input` schema.
|
|
76
|
+
*/
|
|
77
|
+
export function defineTools(tools, options = {}) {
|
|
78
|
+
const definitions = new Map();
|
|
79
|
+
for (const name of Object.keys(tools).sort()) {
|
|
80
|
+
const definition = tools[name];
|
|
81
|
+
assertToolDefinition(name, definition);
|
|
82
|
+
definitions.set(name, definition);
|
|
83
|
+
}
|
|
84
|
+
if (options.instructions !== undefined &&
|
|
85
|
+
typeof options.instructions !== "string") {
|
|
86
|
+
throw new TypeError("defineTools: instructions must be a string");
|
|
87
|
+
}
|
|
88
|
+
let catalog;
|
|
89
|
+
const toolSet = Object.freeze({
|
|
90
|
+
names: Object.freeze([...definitions.keys()]),
|
|
91
|
+
});
|
|
92
|
+
internals.set(toolSet, {
|
|
93
|
+
tool: (name) => definitions.get(name),
|
|
94
|
+
catalog: () => {
|
|
95
|
+
catalog ??= buildCatalog(definitions, options.instructions).catch((error) => {
|
|
96
|
+
catalog = undefined;
|
|
97
|
+
throw error;
|
|
98
|
+
});
|
|
99
|
+
return catalog;
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
return toolSet;
|
|
103
|
+
}
|
|
104
|
+
function assertToolDefinition(name, definition) {
|
|
105
|
+
const problem = (message) => new TypeError(`defineTools: tool "${name}" ${message}`);
|
|
106
|
+
if (!TOOL_NAME_PATTERN.test(name)) {
|
|
107
|
+
throw problem("must be named in lowercase snake_case: a letter, then letters, digits or _ (at most 48 characters)");
|
|
108
|
+
}
|
|
109
|
+
if (!definition || typeof definition !== "object") {
|
|
110
|
+
throw problem("must be an object");
|
|
111
|
+
}
|
|
112
|
+
if (typeof definition.description !== "string" ||
|
|
113
|
+
!definition.description.trim()) {
|
|
114
|
+
throw problem("needs a description");
|
|
115
|
+
}
|
|
116
|
+
if (!isToolRisk(definition.risk)) {
|
|
117
|
+
throw problem('needs a risk: "read", "write" or "destructive"');
|
|
118
|
+
}
|
|
119
|
+
if (!isToolSchema(definition.input)) {
|
|
120
|
+
throw problem("input must be a Standard Schema with JSON Schema support (zod >= 4.2) or { jsonSchema, validate }");
|
|
121
|
+
}
|
|
122
|
+
if (definition.output !== undefined && !isToolSchema(definition.output)) {
|
|
123
|
+
throw problem("output must be a Standard Schema with JSON Schema support (zod >= 4.2) or { jsonSchema, validate }");
|
|
124
|
+
}
|
|
125
|
+
if (typeof definition.handler !== "function") {
|
|
126
|
+
throw problem("needs a handler function");
|
|
127
|
+
}
|
|
128
|
+
if (definition.title !== undefined && typeof definition.title !== "string") {
|
|
129
|
+
throw problem("title must be a string");
|
|
130
|
+
}
|
|
131
|
+
for (const flag of ["idempotent", "openWorld"]) {
|
|
132
|
+
if (definition[flag] !== undefined &&
|
|
133
|
+
typeof definition[flag] !== "boolean") {
|
|
134
|
+
throw problem(`${flag} must be a boolean`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function isRecord(value) {
|
|
139
|
+
return ((typeof value === "object" || typeof value === "function") && value !== null);
|
|
140
|
+
}
|
|
141
|
+
function isPlainToolSchema(value) {
|
|
142
|
+
return (isRecord(value) &&
|
|
143
|
+
!("~standard" in value) &&
|
|
144
|
+
isRecord(value.jsonSchema) &&
|
|
145
|
+
typeof value.validate === "function");
|
|
146
|
+
}
|
|
147
|
+
function isStandardWithJson(value) {
|
|
148
|
+
if (!isRecord(value))
|
|
149
|
+
return false;
|
|
150
|
+
const standard = value["~standard"];
|
|
151
|
+
if (!isRecord(standard) || typeof standard.validate !== "function") {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
const converter = standard.jsonSchema;
|
|
155
|
+
return (isRecord(converter) &&
|
|
156
|
+
typeof converter.input === "function" &&
|
|
157
|
+
typeof converter.output === "function");
|
|
158
|
+
}
|
|
159
|
+
function isToolSchema(value) {
|
|
160
|
+
return isStandardWithJson(value) || isPlainToolSchema(value);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Describe every tool that can be described. A tool whose schema has no
|
|
164
|
+
* object JSON Schema form is left out with a warning (logged here, and
|
|
165
|
+
* reported to the gateway so the deploy prints it) instead of taking the
|
|
166
|
+
* app's other tools down with it.
|
|
167
|
+
*/
|
|
168
|
+
async function buildCatalog(definitions, instructions) {
|
|
169
|
+
const tools = [];
|
|
170
|
+
const warnings = [];
|
|
171
|
+
for (const [name, definition] of definitions) {
|
|
172
|
+
const described = describeTool(name, definition);
|
|
173
|
+
if (typeof described === "string") {
|
|
174
|
+
warnings.push(`${name}: skipped, ${described}`);
|
|
175
|
+
console.warn(`[everyapp] defineTools: tool "${name}" ${described}`);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
tools.push(described);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
...(instructions !== undefined ? { instructions } : {}),
|
|
183
|
+
tools,
|
|
184
|
+
hash: await catalogHash({ instructions, tools }),
|
|
185
|
+
warnings,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/** A tool's descriptor, or why it can't be described. */
|
|
189
|
+
function describeTool(name, definition) {
|
|
190
|
+
const inputSchema = objectJsonSchema(definition.input, "input");
|
|
191
|
+
if (typeof inputSchema === "string")
|
|
192
|
+
return inputSchema;
|
|
193
|
+
const outputSchema = definition.output
|
|
194
|
+
? objectJsonSchema(definition.output, "output")
|
|
195
|
+
: undefined;
|
|
196
|
+
if (typeof outputSchema === "string")
|
|
197
|
+
return outputSchema;
|
|
198
|
+
const annotations = {
|
|
199
|
+
...(definition.idempotent !== undefined
|
|
200
|
+
? { idempotentHint: definition.idempotent }
|
|
201
|
+
: {}),
|
|
202
|
+
...(definition.openWorld !== undefined
|
|
203
|
+
? { openWorldHint: definition.openWorld }
|
|
204
|
+
: {}),
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
name,
|
|
208
|
+
...(definition.title ? { title: definition.title } : {}),
|
|
209
|
+
description: definition.description,
|
|
210
|
+
risk: definition.risk,
|
|
211
|
+
inputSchema,
|
|
212
|
+
...(outputSchema ? { outputSchema } : {}),
|
|
213
|
+
...(Object.keys(annotations).length > 0 ? { annotations } : {}),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* The JSON Schema for one side of a tool: the arguments a client sends
|
|
218
|
+
* (`input`) or the result it receives (`output`), or why there is none.
|
|
219
|
+
*
|
|
220
|
+
* Both sides must describe objects. Unions of objects (zod's `union` and
|
|
221
|
+
* `discriminatedUnion`) come out as a root `anyOf`/`oneOf` without a `type`,
|
|
222
|
+
* so like the MCP SDK this adds `type: "object"` to a typeless input root
|
|
223
|
+
* (MCP arguments are always an object) and to a typeless output root whose
|
|
224
|
+
* every branch is an object.
|
|
225
|
+
*/
|
|
226
|
+
function objectJsonSchema(schema, side) {
|
|
227
|
+
let raw;
|
|
228
|
+
try {
|
|
229
|
+
raw = isPlainToolSchema(schema)
|
|
230
|
+
? schema.jsonSchema
|
|
231
|
+
: schema["~standard"].jsonSchema[side]({ target: JSON_SCHEMA_TARGET });
|
|
232
|
+
// A JSON round trip copies the schema and drops anything JSON can't carry.
|
|
233
|
+
raw = JSON.parse(JSON.stringify(raw));
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
return `${side} has no JSON Schema form: ${error.message}`;
|
|
237
|
+
}
|
|
238
|
+
if (!isRecord(raw) || Array.isArray(raw)) {
|
|
239
|
+
return `${side} has no JSON Schema form`;
|
|
240
|
+
}
|
|
241
|
+
const copy = withoutMcpHeaders(raw);
|
|
242
|
+
if (copy.$schema === DRAFT_2020_12)
|
|
243
|
+
delete copy.$schema;
|
|
244
|
+
if (copy.type === undefined &&
|
|
245
|
+
(side === "input" || isProvablyObjectShaped(copy))) {
|
|
246
|
+
return { type: "object", ...copy };
|
|
247
|
+
}
|
|
248
|
+
if (copy.type !== "object") {
|
|
249
|
+
return `${side} must describe an object (JSON Schema type "object")`;
|
|
250
|
+
}
|
|
251
|
+
return copy;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* A typeless schema that can only match objects: it has object keywords, or
|
|
255
|
+
* every branch of its `oneOf`/`anyOf`/`allOf` is an object. `$ref` is not
|
|
256
|
+
* followed.
|
|
257
|
+
*/
|
|
258
|
+
function isProvablyObjectShaped(schema) {
|
|
259
|
+
if ([
|
|
260
|
+
"properties",
|
|
261
|
+
"patternProperties",
|
|
262
|
+
"additionalProperties",
|
|
263
|
+
"required",
|
|
264
|
+
].some((keyword) => keyword in schema)) {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
for (const keyword of ["oneOf", "anyOf", "allOf"]) {
|
|
268
|
+
const branches = schema[keyword];
|
|
269
|
+
if (Array.isArray(branches) && branches.length > 0) {
|
|
270
|
+
return branches.every((branch) => isRecord(branch) &&
|
|
271
|
+
(branch.type === "object" || isProvablyObjectShaped(branch)));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
function withoutMcpHeaders(value) {
|
|
277
|
+
if (Array.isArray(value))
|
|
278
|
+
return value.map(withoutMcpHeaders);
|
|
279
|
+
if (!isRecord(value))
|
|
280
|
+
return value;
|
|
281
|
+
const out = {};
|
|
282
|
+
for (const [key, member] of Object.entries(value)) {
|
|
283
|
+
if (key !== MCP_HEADER_KEYWORD)
|
|
284
|
+
out[key] = withoutMcpHeaders(member);
|
|
285
|
+
}
|
|
286
|
+
return out;
|
|
287
|
+
}
|
|
288
|
+
/** Run a tool schema's validator. */
|
|
289
|
+
export async function validateWithSchema(schema, value) {
|
|
290
|
+
const result = isPlainToolSchema(schema)
|
|
291
|
+
? await schema.validate(value)
|
|
292
|
+
: await schema["~standard"].validate(value);
|
|
293
|
+
if (result.issues) {
|
|
294
|
+
return { ok: false, issues: result.issues.map(toIssue) };
|
|
295
|
+
}
|
|
296
|
+
return { ok: true, value: result.value };
|
|
297
|
+
}
|
|
298
|
+
function toIssue(issue) {
|
|
299
|
+
const path = (issue.path ?? [])
|
|
300
|
+
.map((segment) => typeof segment === "object" && segment !== null ? segment.key : segment)
|
|
301
|
+
.filter((key) => typeof key === "string" || typeof key === "number");
|
|
302
|
+
return {
|
|
303
|
+
message: String(issue.message),
|
|
304
|
+
...(path.length > 0 ? { path } : {}),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Turn a handler's return value into a tool result. With an output schema,
|
|
309
|
+
* the value must validate and is sent as structured content as well as text.
|
|
310
|
+
*/
|
|
311
|
+
export async function toToolResult(definition, value) {
|
|
312
|
+
if (isToolResult(value)) {
|
|
313
|
+
const structured = definition.output
|
|
314
|
+
? (await toToolResult(definition, value.structured)).structuredContent
|
|
315
|
+
: value.structured;
|
|
316
|
+
if (!isRecord(structured) || Array.isArray(structured)) {
|
|
317
|
+
throw new Error("structured results must be JSON objects");
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
content: [{ type: "text", text: value.text }],
|
|
321
|
+
structuredContent: structured,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (definition.output) {
|
|
325
|
+
const checked = await validateWithSchema(definition.output, value);
|
|
326
|
+
if (!checked.ok) {
|
|
327
|
+
throw new Error(`result does not match the output schema: ${checked.issues
|
|
328
|
+
.map((issue) => issue.message)
|
|
329
|
+
.join("; ")}`);
|
|
330
|
+
}
|
|
331
|
+
if (!isRecord(checked.value) ||
|
|
332
|
+
Array.isArray(checked.value) ||
|
|
333
|
+
typeof checked.value === "function") {
|
|
334
|
+
throw new Error("structured results must be JSON objects");
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
content: [{ type: "text", text: JSON.stringify(checked.value) }],
|
|
338
|
+
structuredContent: checked.value,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
if (typeof value === "string") {
|
|
342
|
+
return { content: [{ type: "text", text: value }] };
|
|
343
|
+
}
|
|
344
|
+
if (value === undefined)
|
|
345
|
+
return { content: [] };
|
|
346
|
+
return { content: [{ type: "text", text: JSON.stringify(value) }] };
|
|
347
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app side of the internal tools contract (../internal/tools.ts).
|
|
3
|
+
*
|
|
4
|
+
* `everyApp()` answers the two reserved paths here, before any app code runs
|
|
5
|
+
* and whether or not the app defines tools:
|
|
6
|
+
*
|
|
7
|
+
* - `/__everyapp/tools/list` needs the gateway's system token for this app
|
|
8
|
+
* (purpose "tools.list"). It describes tools; it never runs them.
|
|
9
|
+
* - `/__everyapp/tools/call` needs an identity token minted for this exact
|
|
10
|
+
* call: `chan: "mcp"` plus a `tc` claim naming the tool and call id. The
|
|
11
|
+
* token's scopes must include the scope the tool's risk requires; `*` does
|
|
12
|
+
* not count, because the ToolBus only ever mints explicit scopes.
|
|
13
|
+
*
|
|
14
|
+
* The perimeter also refuses these paths from outside and strips inbound
|
|
15
|
+
* `x-everyapp-*` headers, so only the gateway's ToolBus ever reaches them.
|
|
16
|
+
*/
|
|
17
|
+
import { type RequestIdentityOptions } from "../internal/index.js";
|
|
18
|
+
import type { ExecutionContextLike } from "./everyApp.js";
|
|
19
|
+
import { type ToolSet } from "./tools.js";
|
|
20
|
+
export interface ToolsEndpointOptions {
|
|
21
|
+
toolSet?: ToolSet;
|
|
22
|
+
/** This app's id, for the masked-error label. */
|
|
23
|
+
appId: string;
|
|
24
|
+
/** How to verify gateway-minted tokens (keys, issuer, dev opt-in). */
|
|
25
|
+
identity: RequestIdentityOptions;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Answer a request to the reserved tools paths, or return null for any other
|
|
29
|
+
* path so the app's own handler runs.
|
|
30
|
+
*/
|
|
31
|
+
export declare function handleToolsRequest(request: Request, env: unknown, ctx: ExecutionContextLike, options: ToolsEndpointOptions): Promise<Response | null>;
|
|
32
|
+
//# sourceMappingURL=toolsEndpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolsEndpoint.d.ts","sourceRoot":"","sources":["../../src/server/toolsEndpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAcL,KAAK,sBAAsB,EAO5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAOL,KAAK,OAAO,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,QAAQ,EAAE,sBAAsB,CAAC;CAClC;AAoFD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,oBAAoB,EACzB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyB1B"}
|