@noodleseed/one 0.138.0 → 0.139.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/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/import.d.ts +4 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +198 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/project-setup.d.ts +1 -1
- package/dist/commands/project-setup.d.ts.map +1 -1
- package/dist/commands/project-setup.js +2 -48
- package/dist/commands/project-setup.js.map +1 -1
- package/dist/commands/service-ops.d.ts.map +1 -1
- package/dist/commands/service-ops.js +44 -51
- package/dist/commands/service-ops.js.map +1 -1
- package/dist/mcp-import.d.ts +22 -0
- package/dist/mcp-import.d.ts.map +1 -0
- package/dist/mcp-import.js +91 -0
- package/dist/mcp-import.js.map +1 -0
- package/dist/self-host-init.d.ts +23 -0
- package/dist/self-host-init.d.ts.map +1 -0
- package/dist/self-host-init.js +315 -0
- package/dist/self-host-init.js.map +1 -0
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +3 -3
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +11 -2
- package/node_modules/@noodle-borg/agent-kit/dist/skill-connect-refs.js +31 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js +3 -2
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-guide.d.ts +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-guide.js +35 -1
- package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -1
- package/node_modules/@noodle-borg/authoring/dist/connections.js +1 -0
- package/node_modules/@noodle-borg/authoring/dist/connectors.d.ts +25 -3
- package/node_modules/@noodle-borg/authoring/dist/connectors.js +82 -7
- package/node_modules/@noodle-borg/authoring/dist/index.d.ts +1 -1
- package/node_modules/@noodle-borg/authoring/dist/model-tool-visibility.js +33 -0
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts +5 -0
- package/node_modules/@noodle-borg/authoring/dist/server.js +7 -2
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-account.js +13 -1
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-bootstrap-authoring.js +30 -1
- package/node_modules/@noodle-borg/connector-defs/dist/call-graph.js +1 -1
- package/node_modules/@noodle-borg/connector-defs/dist/compile-mcp.js +95 -0
- package/node_modules/@noodle-borg/connector-defs/dist/compile.js +4 -0
- package/node_modules/@noodle-borg/connector-defs/dist/customer-routing.js +1 -1
- package/node_modules/@noodle-borg/connector-defs/dist/index.d.ts +1 -1
- package/node_modules/@noodle-borg/connector-defs/dist/schema.d.ts +642 -3
- package/node_modules/@noodle-borg/connector-defs/dist/schema.js +143 -1
- package/node_modules/@noodle-borg/connector-http/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/connector-http/dist/index.js +1 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/config.js +76 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/egress.js +125 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/failure.js +48 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/index.d.ts +3 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/index.js +2 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/mcp-connector.d.ts +12 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/mcp-connector.js +125 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/result.js +55 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/types.d.ts +52 -0
- package/node_modules/@noodle-borg/connector-http/dist/mcp/types.js +10 -0
- package/node_modules/@noodle-borg/connector-http/package.json +4 -1
- package/node_modules/@noodle-borg/openapi-import/dist/index.js +1 -0
- package/node_modules/@noodle-borg/openapi-import/dist/mcp/index.js +4 -0
- package/node_modules/@noodle-borg/openapi-import/dist/mcp/probe.js +165 -0
- package/node_modules/@noodle-borg/openapi-import/dist/mcp/render.js +99 -0
- package/node_modules/@noodle-borg/openapi-import/dist/mcp/snapshot.js +290 -0
- package/node_modules/@noodle-borg/openapi-import/package.json +6 -2
- package/node_modules/@noodle-borg/runtime/dist/connector/types.d.ts +2 -0
- package/node_modules/@noodle-borg/runtime/dist/operation-execution.js +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +8 -5
- package/node_modules/@noodle-borg/service/package.json +1 -1
- package/node_modules/@noodleseed/assistant/package.json +1 -1
- package/package.json +2 -2
|
@@ -20,6 +20,7 @@ export function bind(connector, options) {
|
|
|
20
20
|
: {}),
|
|
21
21
|
...(connector.definitions !== undefined ? { definitions: connector.definitions } : {}),
|
|
22
22
|
...(connector.httpDef !== undefined ? { httpDef: connector.httpDef } : {}),
|
|
23
|
+
...(connector.mcpDef !== undefined ? { mcpDef: connector.mcpDef } : {}),
|
|
23
24
|
binding: { profile: options.profile, connection: options.connection },
|
|
24
25
|
};
|
|
25
26
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CustomerEndpointRef, type JsonSchema, type OperationSignature } from '@noodle-borg/compiler';
|
|
2
|
-
import { type ConnectorFile, type CredentialProfileDef, type HttpConnectorDef } from '@noodle-borg/connector-defs';
|
|
2
|
+
import { type ConnectorFile, type CredentialProfileDef, type HttpConnectorDef, type McpConnectorDef } from '@noodle-borg/connector-defs';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { type ConfigRef } from './config.js';
|
|
5
5
|
import type { ConnectionBinding } from './connection-types.js';
|
|
@@ -86,7 +86,24 @@ export type HttpConnectorOptions = Omit<HttpConnectorDef['http'], 'baseUrl' | 'a
|
|
|
86
86
|
readonly credentialProfiles?: HttpConnectorDef['credentialProfiles'];
|
|
87
87
|
readonly operations: Readonly<Record<string, HttpOperationOptionsWithRefs>>;
|
|
88
88
|
};
|
|
89
|
-
type
|
|
89
|
+
export type McpAuthOptions = Extract<HttpAuthOptions, {
|
|
90
|
+
readonly kind: 'bearer' | 'apiKey' | 'clientCredentials';
|
|
91
|
+
}>;
|
|
92
|
+
type McpOperationOptionsWithRefs = Omit<McpConnectorDef['operations'][string], 'auth' | 'input' | 'output'> & {
|
|
93
|
+
readonly auth?: McpAuthOptions;
|
|
94
|
+
readonly input?: OperationIoOptions;
|
|
95
|
+
readonly output?: OperationIoOptions;
|
|
96
|
+
};
|
|
97
|
+
export type McpConnectorOptions = Omit<McpConnectorDef['mcp'], 'endpoint' | 'allowedOrigins' | 'auth'> & {
|
|
98
|
+
readonly endpoint: string | ConfigRef;
|
|
99
|
+
readonly allowedOrigins?: readonly (string | ConfigRef)[];
|
|
100
|
+
readonly auth?: McpAuthOptions;
|
|
101
|
+
readonly credentialProfiles?: McpConnectorDef['credentialProfiles'];
|
|
102
|
+
readonly operations: Readonly<Record<string, McpOperationOptionsWithRefs>>;
|
|
103
|
+
};
|
|
104
|
+
type DeclaredCredentialProfileKeys<Options extends {
|
|
105
|
+
readonly credentialProfiles?: unknown;
|
|
106
|
+
}> = Options extends {
|
|
90
107
|
readonly credentialProfiles: infer Profiles;
|
|
91
108
|
} ? Extract<keyof Profiles, string> : never;
|
|
92
109
|
export interface ConnectorOperationOptions {
|
|
@@ -142,6 +159,8 @@ export interface ConnectorRef<CredentialProfileKey extends string = string> {
|
|
|
142
159
|
readonly definitions?: Readonly<Record<string, ConnectorOpDefinition>>;
|
|
143
160
|
/** HTTP fulfilment (present for connectors declared with `.http()`), emitted to the catalog verbatim. */
|
|
144
161
|
readonly httpDef?: HttpConnectorDef;
|
|
162
|
+
/** MCP fulfilment (present for connectors declared with `.mcp()`), emitted to the catalog verbatim. */
|
|
163
|
+
readonly mcpDef?: McpConnectorDef;
|
|
145
164
|
}
|
|
146
165
|
/**
|
|
147
166
|
* The connector-catalog document the SDK emits for the compiler. It is the canonical `ConnectorFile` from
|
|
@@ -160,8 +179,9 @@ export declare class ConnectorBuilder<CredentialProfileKey extends string = neve
|
|
|
160
179
|
readonly operations: Readonly<Record<string, OperationSignature>>;
|
|
161
180
|
readonly definitions: Readonly<Record<string, ConnectorOpDefinition>>;
|
|
162
181
|
readonly httpDef?: HttpConnectorDef;
|
|
182
|
+
readonly mcpDef?: McpConnectorDef;
|
|
163
183
|
readonly credentialProfiles?: Readonly<Record<CredentialProfileKey, CredentialProfileDef>>;
|
|
164
|
-
constructor(id: string, version: string, operations?: Readonly<Record<string, OperationSignature>>, definitions?: Readonly<Record<string, ConnectorOpDefinition>>, httpDef?: HttpConnectorDef, credentialProfiles?: Readonly<Record<CredentialProfileKey, CredentialProfileDef
|
|
184
|
+
constructor(id: string, version: string, operations?: Readonly<Record<string, OperationSignature>>, definitions?: Readonly<Record<string, ConnectorOpDefinition>>, httpDef?: HttpConnectorDef, credentialProfiles?: Readonly<Record<CredentialProfileKey, CredentialProfileDef>>, mcpDef?: McpConnectorDef);
|
|
165
185
|
/** Declare the credential profiles supported by a curated signature ref or compute connector. */
|
|
166
186
|
credentials<const Profiles extends Readonly<Record<string, CredentialProfileDef>>>(profiles: Profiles): ConnectorBuilder<Extract<keyof Profiles, string>>;
|
|
167
187
|
/** Declare an operation by signature only (fulfilment supplied elsewhere, e.g. a catalog by `id@version`). */
|
|
@@ -173,6 +193,8 @@ export declare class ConnectorBuilder<CredentialProfileKey extends string = neve
|
|
|
173
193
|
* `.provides()`-d. The typed options are validated against the canonical schema at author time.
|
|
174
194
|
*/
|
|
175
195
|
http<const Options extends HttpConnectorOptions>(options: Options): ConnectorBuilder<DeclaredCredentialProfileKeys<Options>>;
|
|
196
|
+
/** Declare a governed remote MCP connector from an imported, frozen upstream tool snapshot. */
|
|
197
|
+
mcp<const Options extends McpConnectorOptions>(options: Options): ConnectorBuilder<DeclaredCredentialProfileKeys<Options>>;
|
|
176
198
|
/** Declare a sandboxed-compute operation: `run` is your function, shipped as the connector's `code`. */
|
|
177
199
|
compute(name: string, options: ComputeOperationOptions): ConnectorBuilder<CredentialProfileKey>;
|
|
178
200
|
}
|
|
@@ -48,8 +48,9 @@ export class ConnectorBuilder {
|
|
|
48
48
|
operations;
|
|
49
49
|
definitions;
|
|
50
50
|
httpDef;
|
|
51
|
+
mcpDef;
|
|
51
52
|
credentialProfiles;
|
|
52
|
-
constructor(id, version, operations = {}, definitions = {}, httpDef, credentialProfiles) {
|
|
53
|
+
constructor(id, version, operations = {}, definitions = {}, httpDef, credentialProfiles, mcpDef) {
|
|
53
54
|
this.id = id;
|
|
54
55
|
this.version = version;
|
|
55
56
|
this.operations = operations;
|
|
@@ -57,20 +58,22 @@ export class ConnectorBuilder {
|
|
|
57
58
|
// Assign conditionally (not `= undefined`) to satisfy exactOptionalPropertyTypes.
|
|
58
59
|
if (httpDef !== undefined)
|
|
59
60
|
this.httpDef = httpDef;
|
|
60
|
-
|
|
61
|
+
if (mcpDef !== undefined)
|
|
62
|
+
this.mcpDef = mcpDef;
|
|
63
|
+
const declaredProfiles = credentialProfiles ?? httpDef?.credentialProfiles ?? mcpDef?.credentialProfiles;
|
|
61
64
|
if (declaredProfiles !== undefined) {
|
|
62
65
|
this.credentialProfiles = declaredProfiles;
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
/** Declare the credential profiles supported by a curated signature ref or compute connector. */
|
|
66
69
|
credentials(profiles) {
|
|
67
|
-
if (this.httpDef !== undefined) {
|
|
68
|
-
throw new Error(`connector "${this.id}"
|
|
70
|
+
if (this.httpDef !== undefined || this.mcpDef !== undefined) {
|
|
71
|
+
throw new Error(`connector "${this.id}" owns its transport — declare credentialProfiles inside the transport options`);
|
|
69
72
|
}
|
|
70
73
|
if (this.credentialProfiles !== undefined) {
|
|
71
74
|
throw new Error(`connector "${this.id}" already declares credential profiles`);
|
|
72
75
|
}
|
|
73
|
-
return new ConnectorBuilder(this.id, this.version, this.operations, this.definitions, undefined, { ...profiles });
|
|
76
|
+
return new ConnectorBuilder(this.id, this.version, this.operations, this.definitions, undefined, { ...profiles }, undefined);
|
|
74
77
|
}
|
|
75
78
|
/** Declare an operation by signature only (fulfilment supplied elsewhere, e.g. a catalog by `id@version`). */
|
|
76
79
|
operation(name, options) {
|
|
@@ -81,7 +84,7 @@ export class ConnectorBuilder {
|
|
|
81
84
|
input: toOperationIoSchema(options.input, 'input', `${this.id}.${name}`),
|
|
82
85
|
output: toOperationIoSchema(options.output, 'output', `${this.id}.${name}`),
|
|
83
86
|
},
|
|
84
|
-
}, this.definitions, this.httpDef, this.credentialProfiles);
|
|
87
|
+
}, this.definitions, this.httpDef, this.credentialProfiles, this.mcpDef);
|
|
85
88
|
}
|
|
86
89
|
/**
|
|
87
90
|
* Declare this as an **HTTP connector**: transport (`baseUrl`/`allowedOrigins`), `bearer`/`apiKey` auth
|
|
@@ -93,6 +96,9 @@ export class ConnectorBuilder {
|
|
|
93
96
|
if (this.credentialProfiles !== undefined) {
|
|
94
97
|
throw new Error(`connector "${this.id}" already uses .credentials(...) — HTTP connectors declare credentialProfiles inside .http(...)`);
|
|
95
98
|
}
|
|
99
|
+
if (this.mcpDef !== undefined) {
|
|
100
|
+
throw new Error(`connector "${this.id}" is already an .mcp() connector — a connector has one engine`);
|
|
101
|
+
}
|
|
96
102
|
if (Object.keys(this.definitions).length > 0) {
|
|
97
103
|
throw new Error(`connector "${this.id}" already has .compute() operations — a connector is HTTP or compute, not both`);
|
|
98
104
|
}
|
|
@@ -120,11 +126,80 @@ export class ConnectorBuilder {
|
|
|
120
126
|
}
|
|
121
127
|
return new ConnectorBuilder(this.id, this.version, signatures, this.definitions, def);
|
|
122
128
|
}
|
|
129
|
+
/** Declare a governed remote MCP connector from an imported, frozen upstream tool snapshot. */
|
|
130
|
+
mcp(options) {
|
|
131
|
+
if (this.credentialProfiles !== undefined) {
|
|
132
|
+
throw new Error(`connector "${this.id}" already uses .credentials(...) — MCP connectors declare credentialProfiles inside .mcp(...)`);
|
|
133
|
+
}
|
|
134
|
+
if (this.httpDef !== undefined) {
|
|
135
|
+
throw new Error(`connector "${this.id}" is already an .http() connector — a connector has one engine`);
|
|
136
|
+
}
|
|
137
|
+
if (Object.keys(this.definitions).length > 0) {
|
|
138
|
+
throw new Error(`connector "${this.id}" already has .compute() operations — a connector is MCP or compute, not both`);
|
|
139
|
+
}
|
|
140
|
+
const operations = {};
|
|
141
|
+
for (const [name, operation] of Object.entries(options.operations)) {
|
|
142
|
+
const output = operation.result === 'text' && operation.output === undefined
|
|
143
|
+
? {
|
|
144
|
+
type: 'object',
|
|
145
|
+
properties: { text: { type: 'string' } },
|
|
146
|
+
required: ['text'],
|
|
147
|
+
additionalProperties: false,
|
|
148
|
+
}
|
|
149
|
+
: toOperationIoSchema(operation.output, 'output', `${this.id}.${name}`);
|
|
150
|
+
operations[name] = {
|
|
151
|
+
...operation,
|
|
152
|
+
result: operation.result ?? 'structured',
|
|
153
|
+
input: toOperationIoSchema(operation.input, 'input', `${this.id}.${name}`),
|
|
154
|
+
output,
|
|
155
|
+
...(operation.auth === undefined
|
|
156
|
+
? {}
|
|
157
|
+
: {
|
|
158
|
+
auth: normalizeAuth(operation.auth, `connectors.${this.id}.operations.${name}.auth`),
|
|
159
|
+
}),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const { credentialProfiles, operations: _operations, ...mcpOptions } = options;
|
|
163
|
+
const def = {
|
|
164
|
+
id: this.id,
|
|
165
|
+
version: this.version,
|
|
166
|
+
kind: 'custom',
|
|
167
|
+
...(credentialProfiles === undefined ? {} : { credentialProfiles }),
|
|
168
|
+
mcp: {
|
|
169
|
+
...mcpOptions,
|
|
170
|
+
endpoint: normalizeVariableOrString(options.endpoint, `connectors.${this.id}.mcp.endpoint`),
|
|
171
|
+
...(options.allowedOrigins === undefined
|
|
172
|
+
? {}
|
|
173
|
+
: {
|
|
174
|
+
allowedOrigins: options.allowedOrigins.map((origin, index) => normalizeVariableOrString(origin, `connectors.${this.id}.mcp.allowedOrigins.${index}`)),
|
|
175
|
+
}),
|
|
176
|
+
...(options.auth === undefined
|
|
177
|
+
? {}
|
|
178
|
+
: {
|
|
179
|
+
auth: normalizeAuth(options.auth, `connectors.${this.id}.mcp.auth`),
|
|
180
|
+
}),
|
|
181
|
+
},
|
|
182
|
+
operations,
|
|
183
|
+
};
|
|
184
|
+
validateCatalog({ connectors: [def] });
|
|
185
|
+
const signatures = {};
|
|
186
|
+
for (const [name, operation] of Object.entries(operations)) {
|
|
187
|
+
signatures[name] = {
|
|
188
|
+
type: operation.type,
|
|
189
|
+
input: normalizeOperationIoSchema(operation.input),
|
|
190
|
+
output: normalizeOperationIoSchema(operation.output),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return new ConnectorBuilder(this.id, this.version, signatures, this.definitions, undefined, undefined, def);
|
|
194
|
+
}
|
|
123
195
|
/** Declare a sandboxed-compute operation: `run` is your function, shipped as the connector's `code`. */
|
|
124
196
|
compute(name, options) {
|
|
125
197
|
if (this.httpDef) {
|
|
126
198
|
throw new Error(`connector "${this.id}" is already an .http() connector — a connector is HTTP or compute, not both`);
|
|
127
199
|
}
|
|
200
|
+
if (this.mcpDef) {
|
|
201
|
+
throw new Error(`connector "${this.id}" is already an .mcp() connector — a connector is MCP or compute, not both`);
|
|
202
|
+
}
|
|
128
203
|
const type = options.type ?? 'read';
|
|
129
204
|
const input = toOperationIoSchema(options.input, 'input', `${this.id}.${name}`);
|
|
130
205
|
const output = toOperationIoSchema(options.output, 'output', `${this.id}.${name}`);
|
|
@@ -139,7 +214,7 @@ export class ConnectorBuilder {
|
|
|
139
214
|
...(options.limits ? { limits: options.limits } : {}),
|
|
140
215
|
...(options.calls ? { calls: options.calls } : {}),
|
|
141
216
|
},
|
|
142
|
-
}, undefined, this.credentialProfiles);
|
|
217
|
+
}, undefined, this.credentialProfiles, undefined);
|
|
143
218
|
}
|
|
144
219
|
}
|
|
145
220
|
function rejectUnsafeActionRetry(id, options) {
|
|
@@ -5,7 +5,7 @@ export type { AgentCapabilityKind, AgentCapabilityRef, AgentExampleSource, Agent
|
|
|
5
5
|
export { type AssistantAccess, type AssistantCapability, type AssistantLabels, type AssistantLayoutMode, type AssistantModel, type AssistantPosition, type AssistantPresentationOptions, type AssistantPresentationTone, type AssistantSurfaceConfig, type AssistantSurfaceMode, type AssistantThemeMode, type AssistantUiOptions, type AuthenticatedWebsiteAccess, type AuthenticatedWebsiteInput, authenticatedWebsite, type CapabilityRef, type EmbeddedAssistantConfig, type EmbeddedAssistantOptions, embeddedAssistant, type NoodleManagedModel, noodleManaged, type OpenAICompatibleModel, type OpenAICompatibleModelInput, openAICompatible, type PublicWebsiteAccess, type PublicWebsiteInput, publicWebsite, } from './assistant.js';
|
|
6
6
|
export { type ConfigRef, type ConfigRefKind, secret, variable, } from './config.js';
|
|
7
7
|
export { type BoundConnectorRef, bind, type ConnectionBinding, type ConnectionRef, type ConnectionSource, clientCredentials, connection, externalExchange, type GoogleWorkloadIdentityAccess, googleWorkloadIdentity, managedSecret, } from './connections.js';
|
|
8
|
-
export { type ComputeHost, type ComputeLimits, type ComputeOperationOptions, ConnectorBuilder, type ConnectorCatalogDoc, type ConnectorOpDefinition, type ConnectorOperationOptions, type ConnectorRef, connector, type HttpConnectorOptions, } from './connectors.js';
|
|
8
|
+
export { type ComputeHost, type ComputeLimits, type ComputeOperationOptions, ConnectorBuilder, type ConnectorCatalogDoc, type ConnectorOpDefinition, type ConnectorOperationOptions, type ConnectorRef, connector, type HttpConnectorOptions, type McpAuthOptions, type McpConnectorOptions, } from './connectors.js';
|
|
9
9
|
export type { AmbientContextOptions, AmbientProviderContext, ServerContextOptions, } from './context.js';
|
|
10
10
|
export { type CustomerAuth, type CustomerAuthClaimMap, type CustomerAuthRouting, type CustomerEndpointClaimMapping, customerAuth, type FederatedOidcIssuer, } from './customer-auth.js';
|
|
11
11
|
export { type CustomerEndpointPolicy, type CustomerEndpointRef, customerEndpoint, } from './customer-endpoint.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const ANNOTATION = 'x-noodleseed-model-latest-message-includes-any';
|
|
2
|
+
const MAX_PHRASES = 32;
|
|
3
|
+
const MAX_PHRASE_CHARS = 128;
|
|
4
|
+
export function manifestToolAnnotations(options) {
|
|
5
|
+
if (Object.hasOwn(options.annotations ?? {}, ANNOTATION)) {
|
|
6
|
+
throw new Error(`Use modelVisibility.latestMessageIncludesAny instead of the reserved ${ANNOTATION} annotation.`);
|
|
7
|
+
}
|
|
8
|
+
if (options.modelVisibility === undefined) {
|
|
9
|
+
return options.annotations ? { annotations: { ...options.annotations } } : {};
|
|
10
|
+
}
|
|
11
|
+
const phrases = options.modelVisibility.latestMessageIncludesAny;
|
|
12
|
+
if (phrases.length < 1 || phrases.length > MAX_PHRASES) {
|
|
13
|
+
throw new Error(`modelVisibility.latestMessageIncludesAny must contain 1-${MAX_PHRASES} literal phrases.`);
|
|
14
|
+
}
|
|
15
|
+
const trimmed = phrases.map((phrase) => phrase.trim());
|
|
16
|
+
const normalized = trimmed.map(normalize);
|
|
17
|
+
if (trimmed.some((phrase, index) => phrase.length > MAX_PHRASE_CHARS || normalized[index]?.length === 0)) {
|
|
18
|
+
throw new Error(`modelVisibility.latestMessageIncludesAny phrases must contain text and be at most ${MAX_PHRASE_CHARS} characters.`);
|
|
19
|
+
}
|
|
20
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
21
|
+
throw new Error('modelVisibility.latestMessageIncludesAny phrases must be unique.');
|
|
22
|
+
}
|
|
23
|
+
return { annotations: { ...options.annotations, [ANNOTATION]: trimmed } };
|
|
24
|
+
}
|
|
25
|
+
function normalize(value) {
|
|
26
|
+
return value
|
|
27
|
+
.normalize('NFKC')
|
|
28
|
+
.toLocaleLowerCase('en-US')
|
|
29
|
+
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
|
30
|
+
.trim()
|
|
31
|
+
.replace(/\s+/gu, ' ');
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=model-tool-visibility.js.map
|
|
@@ -132,6 +132,11 @@ export interface ToolOptions {
|
|
|
132
132
|
readonly input: JsonSchema | z.ZodType;
|
|
133
133
|
readonly output?: JsonSchema | z.ZodType;
|
|
134
134
|
readonly annotations?: Readonly<Record<string, unknown>>;
|
|
135
|
+
/** Deterministic model-discovery constraints. These do not grant invocation authority. */
|
|
136
|
+
readonly modelVisibility?: {
|
|
137
|
+
/** Show this tool to the model only when the latest user message contains one of these literals. */
|
|
138
|
+
readonly latestMessageIncludesAny: readonly string[];
|
|
139
|
+
};
|
|
135
140
|
/**
|
|
136
141
|
* Tool-surface visibility (SEP-1865 `_meta.ui.visibility`). Default `['model', 'app']`. Set `['app']`
|
|
137
142
|
* for a **UI-only helper** — discoverable with app-only metadata so hosts can hide it from the model
|
|
@@ -10,6 +10,7 @@ import { manifestContext } from './context.js';
|
|
|
10
10
|
import { manifestCustomerAuth } from './customer-auth.js';
|
|
11
11
|
import { toJsonSchema } from './json-schema.js';
|
|
12
12
|
import { manifestKnowledge } from './knowledge.js';
|
|
13
|
+
import { manifestToolAnnotations } from './model-tool-visibility.js';
|
|
13
14
|
import { recordFulfilment, recordTool, } from './recording.js';
|
|
14
15
|
const WIDGET_RESULT_META_KEY = '__noodleResultMeta';
|
|
15
16
|
export function server(name, options, definitions = []) {
|
|
@@ -142,7 +143,7 @@ class ServerBuilder {
|
|
|
142
143
|
...(tool.options.contextProvider ? { contextProvider: true } : {}),
|
|
143
144
|
inputSchema: toJsonSchema(tool.options.input, 'input'),
|
|
144
145
|
...(tool.options.output ? { outputSchema: toJsonSchema(tool.options.output) } : {}),
|
|
145
|
-
...(tool.options
|
|
146
|
+
...manifestToolAnnotations(tool.options),
|
|
146
147
|
...(tool.options.visibility?.length ? { visibility: [...tool.options.visibility] } : {}),
|
|
147
148
|
fulfilment: {
|
|
148
149
|
steps: recorded.steps,
|
|
@@ -251,7 +252,7 @@ class ServerBuilder {
|
|
|
251
252
|
}
|
|
252
253
|
toConnectorCatalog() {
|
|
253
254
|
// `use ∪ provides` is the authoritative emit set: each connector carries its own fulfilment — an
|
|
254
|
-
// HTTP def
|
|
255
|
+
// HTTP/MCP transport def or compute definitions. Signature-only connectors are skipped.
|
|
255
256
|
const connectors = [];
|
|
256
257
|
const seen = new Set();
|
|
257
258
|
for (const c of [...Object.values(this.connectors), ...Object.values(this.provided)]) {
|
|
@@ -262,6 +263,10 @@ class ServerBuilder {
|
|
|
262
263
|
connectors.push(c.httpDef);
|
|
263
264
|
continue;
|
|
264
265
|
}
|
|
266
|
+
if (c.mcpDef) {
|
|
267
|
+
connectors.push(c.mcpDef);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
265
270
|
const definitions = c.definitions;
|
|
266
271
|
if (definitions && Object.keys(definitions).length > 0) {
|
|
267
272
|
const credentialProfiles = c.credentialProfiles;
|
|
@@ -110,7 +110,7 @@ export const CATALOG_ACCOUNT = [
|
|
|
110
110
|
},
|
|
111
111
|
{
|
|
112
112
|
name: 'init',
|
|
113
|
-
summary: '
|
|
113
|
+
summary: 'Initialize a service profile or the local open-core Compose stack.',
|
|
114
114
|
arguments: [],
|
|
115
115
|
flags: [
|
|
116
116
|
{
|
|
@@ -128,6 +128,18 @@ export const CATALOG_ACCOUNT = [
|
|
|
128
128
|
type: 'boolean',
|
|
129
129
|
summary: 'Overwrite a changed existing config.',
|
|
130
130
|
},
|
|
131
|
+
{
|
|
132
|
+
...OPTIONAL_FLAG,
|
|
133
|
+
name: 'compose',
|
|
134
|
+
type: 'boolean',
|
|
135
|
+
summary: 'Generate the local Docker Compose state for the open-core profile.',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
...OPTIONAL_FLAG,
|
|
139
|
+
name: 'replace-secrets',
|
|
140
|
+
type: 'boolean',
|
|
141
|
+
summary: 'Rotate all generated secrets; requires --compose.',
|
|
142
|
+
},
|
|
131
143
|
],
|
|
132
144
|
},
|
|
133
145
|
{
|
|
@@ -129,7 +129,7 @@ export const CATALOG_BOOTSTRAP_AUTHORING = [
|
|
|
129
129
|
name: 'import',
|
|
130
130
|
section: 'build',
|
|
131
131
|
helpRank: 8,
|
|
132
|
-
summary: 'Scaffold starter code from
|
|
132
|
+
summary: 'Scaffold starter code from OpenAPI or a frozen upstream MCP tool snapshot.',
|
|
133
133
|
arguments: [],
|
|
134
134
|
flags: [],
|
|
135
135
|
subcommands: [
|
|
@@ -158,6 +158,35 @@ export const CATALOG_BOOTSTRAP_AUTHORING = [
|
|
|
158
158
|
FORCE_FLAG,
|
|
159
159
|
],
|
|
160
160
|
},
|
|
161
|
+
{
|
|
162
|
+
name: 'mcp',
|
|
163
|
+
summary: 'Import a remote MCP tool snapshot into a governed TypeScript project.',
|
|
164
|
+
arguments: [
|
|
165
|
+
{
|
|
166
|
+
name: 'url',
|
|
167
|
+
type: 'string',
|
|
168
|
+
summary: 'Remote Streamable HTTP MCP endpoint.',
|
|
169
|
+
required: true,
|
|
170
|
+
variadic: false,
|
|
171
|
+
sensitive: false,
|
|
172
|
+
constraints: {},
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
flags: [
|
|
176
|
+
stringFlag('output', '<dir>', 'Generated project directory.', {
|
|
177
|
+
constraints: { default: 'noodle-mcp-app' },
|
|
178
|
+
}),
|
|
179
|
+
stringFlag('name', '<slug>', 'Generated server and connector name.', {
|
|
180
|
+
constraints: { default: 'mcp-app' },
|
|
181
|
+
}),
|
|
182
|
+
stringFlag('prefix', '<name>', 'Prefix imported operation and outward tool names.'),
|
|
183
|
+
stringFlag('header-env', '<header>=<ENV_NAME>', 'Read one import credential from the named environment variable; never persist its value.'),
|
|
184
|
+
booleanFlag('check', 'Compare the live tool surface with the saved snapshot without writing.'),
|
|
185
|
+
FORCE_FLAG,
|
|
186
|
+
JSON_FLAG,
|
|
187
|
+
],
|
|
188
|
+
jsonOutput: { mode: 'single' },
|
|
189
|
+
},
|
|
161
190
|
],
|
|
162
191
|
local: true,
|
|
163
192
|
},
|
|
@@ -8,7 +8,7 @@ export function validateComputeCallGraph(defs, targets, errors) {
|
|
|
8
8
|
graph.set(key, graph.get(key) ?? new Set());
|
|
9
9
|
paths.set(key, `connectors.${def.id}.operations.${opName}.calls`);
|
|
10
10
|
}
|
|
11
|
-
if ('http' in def)
|
|
11
|
+
if ('http' in def || 'mcp' in def)
|
|
12
12
|
continue;
|
|
13
13
|
for (const [opName, op] of Object.entries(def.operations)) {
|
|
14
14
|
const from = operationIdentityKey(def.id, def.version, opName);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { McpConnector, } from '@noodle-borg/connector-http';
|
|
2
|
+
import { collectVariablesFromHttpAuth } from './auth-variables.js';
|
|
3
|
+
import { addAuthBinding, toAuthScheme } from './compile-auth.js';
|
|
4
|
+
import { toSignature } from './compile-http.js';
|
|
5
|
+
import { catalogCredentialMetadata } from './credential-profiles.js';
|
|
6
|
+
import { collectVariableExpression, isVariableExpression } from './variables.js';
|
|
7
|
+
/** Compile one frozen upstream MCP tool snapshot into the ordinary Connector runtime port. */
|
|
8
|
+
export function compileMcpConnector(def, mode, errors, catalog, connectors, secretBindings, variableBindings) {
|
|
9
|
+
const endpoint = def.mcp.endpoint;
|
|
10
|
+
const allowedOrigins = def.mcp.allowedOrigins ?? (isVariableExpression(endpoint) ? [] : [endpoint]);
|
|
11
|
+
collectVariableExpression(endpoint, variableBindings);
|
|
12
|
+
for (const origin of allowedOrigins)
|
|
13
|
+
collectVariableExpression(origin, variableBindings);
|
|
14
|
+
if (def.mcp.auth !== undefined)
|
|
15
|
+
collectVariablesFromHttpAuth(def.mcp.auth, variableBindings);
|
|
16
|
+
if (isVariableExpression(endpoint) && def.mcp.allowedOrigins === undefined) {
|
|
17
|
+
errors.push({
|
|
18
|
+
code: 'variable_mcp_endpoint_requires_allowed_origins',
|
|
19
|
+
path: `connectors.${def.id}.mcp.allowedOrigins`,
|
|
20
|
+
message: 'mcp.allowedOrigins is required when mcp.endpoint is a managed variable',
|
|
21
|
+
});
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const signatures = {};
|
|
25
|
+
const operations = {};
|
|
26
|
+
for (const [operationName, operation] of Object.entries(def.operations)) {
|
|
27
|
+
const base = `connectors.${def.id}.operations.${operationName}`;
|
|
28
|
+
const signature = toSignature(operation.type, operation.input, operation.output);
|
|
29
|
+
signatures[operationName] = signature;
|
|
30
|
+
if (operation.auth !== undefined)
|
|
31
|
+
collectVariablesFromHttpAuth(operation.auth, variableBindings);
|
|
32
|
+
operations[operationName] = {
|
|
33
|
+
upstreamTool: operation.tool,
|
|
34
|
+
signature,
|
|
35
|
+
...(operation.result === 'structured' ? { upstreamOutputSchema: signature.output } : {}),
|
|
36
|
+
...(operation.auth === undefined ? {} : { auth: mcpAuthScheme(operation.auth) }),
|
|
37
|
+
...(operation.limits?.maxResponseBytes === undefined
|
|
38
|
+
? {}
|
|
39
|
+
: { maxResponseBytes: operation.limits.maxResponseBytes }),
|
|
40
|
+
...(operation.fake === undefined ? {} : { fake: operation.fake }),
|
|
41
|
+
};
|
|
42
|
+
addAuthBinding({
|
|
43
|
+
auth: operation.auth,
|
|
44
|
+
connectorId: def.id,
|
|
45
|
+
connectorVersion: def.version,
|
|
46
|
+
operation: operationName,
|
|
47
|
+
path: `${base}.auth`,
|
|
48
|
+
allowedOrigins: literalOrigins(allowedOrigins),
|
|
49
|
+
secretBindings,
|
|
50
|
+
errors,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catalog.push({
|
|
54
|
+
id: def.id,
|
|
55
|
+
version: def.version,
|
|
56
|
+
kind: def.kind ?? 'custom',
|
|
57
|
+
...catalogCredentialMetadata(def),
|
|
58
|
+
operations: signatures,
|
|
59
|
+
});
|
|
60
|
+
addAuthBinding({
|
|
61
|
+
auth: def.mcp.auth,
|
|
62
|
+
connectorId: def.id,
|
|
63
|
+
connectorVersion: def.version,
|
|
64
|
+
path: `connectors.${def.id}.mcp.auth`,
|
|
65
|
+
allowedOrigins: literalOrigins(allowedOrigins),
|
|
66
|
+
secretBindings,
|
|
67
|
+
errors,
|
|
68
|
+
});
|
|
69
|
+
const config = {
|
|
70
|
+
id: def.id,
|
|
71
|
+
version: def.version,
|
|
72
|
+
endpoint,
|
|
73
|
+
...(def.mcp.allowedOrigins === undefined ? {} : { allowedOrigins: def.mcp.allowedOrigins }),
|
|
74
|
+
...(def.mcp.auth === undefined ? {} : { auth: mcpAuthScheme(def.mcp.auth) }),
|
|
75
|
+
...(def.mcp.timeoutMs === undefined ? {} : { timeoutMs: def.mcp.timeoutMs }),
|
|
76
|
+
...(def.mcp.maxResponseBytes === undefined
|
|
77
|
+
? {}
|
|
78
|
+
: { maxResponseBytes: def.mcp.maxResponseBytes }),
|
|
79
|
+
...(def.mcp.protocol === undefined ? {} : { protocol: def.mcp.protocol }),
|
|
80
|
+
...(mode === 'fake' ? { fakeMode: true } : {}),
|
|
81
|
+
operations,
|
|
82
|
+
};
|
|
83
|
+
connectors.push(new McpConnector(config));
|
|
84
|
+
}
|
|
85
|
+
function mcpAuthScheme(auth) {
|
|
86
|
+
const scheme = toAuthScheme(auth);
|
|
87
|
+
if (scheme.kind === 'cookie') {
|
|
88
|
+
throw new Error('delegated session cookie auth is not valid for an MCP connector');
|
|
89
|
+
}
|
|
90
|
+
return scheme;
|
|
91
|
+
}
|
|
92
|
+
function literalOrigins(origins) {
|
|
93
|
+
return origins.filter((origin) => !isVariableExpression(origin));
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=compile-mcp.js.map
|
|
@@ -3,6 +3,7 @@ import { CodeConnector, DEFAULT_LIMITS, QuickJsComputeEngine, } from '@noodle-bo
|
|
|
3
3
|
import { parse as parseYaml } from 'yaml';
|
|
4
4
|
import { validateComputeCallGraph } from './call-graph.js';
|
|
5
5
|
import { compileHttpConnector, toSignature } from './compile-http.js';
|
|
6
|
+
import { compileMcpConnector } from './compile-mcp.js';
|
|
6
7
|
import { catalogCredentialMetadata } from './credential-profiles.js';
|
|
7
8
|
import { collectCatalogCustomerRouting } from './customer-routing.js';
|
|
8
9
|
import { connectorIdentityKey } from './identity-key.js';
|
|
@@ -62,6 +63,9 @@ export function compileConnectors(source, options = {}) {
|
|
|
62
63
|
if ('http' in def) {
|
|
63
64
|
compileHttpConnector(def, mode, errors, catalog, connectors, secretBindings, variableBindings);
|
|
64
65
|
}
|
|
66
|
+
else if ('mcp' in def) {
|
|
67
|
+
compileMcpConnector(def, mode, errors, catalog, connectors, secretBindings, variableBindings);
|
|
68
|
+
}
|
|
65
69
|
else {
|
|
66
70
|
compileComputeConnector(def, computeEngine, targets, errors, catalog, connectors);
|
|
67
71
|
}
|
|
@@ -57,7 +57,7 @@ export function collectCatalogCustomerRouting(definitions, errors) {
|
|
|
57
57
|
actionEndpoints.add(def.http.baseUrl.name);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
else {
|
|
60
|
+
else if (!('mcp' in def)) {
|
|
61
61
|
const computeOperation = def.operations[operationName];
|
|
62
62
|
if (computeOperation?.calls === undefined) {
|
|
63
63
|
visiting.delete(key);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { type ClientCredentialsBinding, type ClientCredentialsCustomBinding, type CompileConnectorsOptions, type CompileConnectorsResult, type ConnectorCompileError, compileConnectors, type DelegatedOAuthBinding, type DelegatedTokenExchangeBinding, type SecretBinding, } from './compile.js';
|
|
2
2
|
export { type DelegatedTokenExchangeIdentityContext, delegatedTokenExchangeIdentityErrors, type ServerCustomerIdentitySources, } from './delegated-token-exchange-identity.js';
|
|
3
|
-
export { type ComputeConnectorDef, type ComputeOperationDef, type ConnectorDef, type ConnectorFile, type CredentialProfileDef, connectorFileSchema, type HttpAuthDef, type HttpConnectorDef, type HttpOperationDef, } from './schema.js';
|
|
3
|
+
export { type ComputeConnectorDef, type ComputeOperationDef, type ConnectorDef, type ConnectorFile, type CredentialProfileDef, connectorFileSchema, type HttpAuthDef, type HttpConnectorDef, type HttpOperationDef, type McpConnectorDef, type McpOperationDef, } from './schema.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|