@zackbart/connecta 0.10.1 → 0.10.3
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/AGENTS.md +113 -0
- package/CHANGELOG.md +70 -0
- package/README.md +53 -9
- package/bin/connecta.mjs +272 -0
- package/dist/catalog-service.d.ts +40 -1
- package/dist/catalog-service.d.ts.map +1 -1
- package/dist/catalog-service.js +137 -12
- package/dist/catalog-service.js.map +1 -1
- package/dist/catalog.d.ts +17 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +113 -13
- package/dist/catalog.js.map +1 -1
- package/dist/errors.d.ts +28 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -1
- package/dist/execute.d.ts +45 -1
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +265 -68
- package/dist/execute.js.map +1 -1
- package/dist/invocation.d.ts.map +1 -1
- package/dist/invocation.js +34 -6
- package/dist/invocation.js.map +1 -1
- package/dist/meta-tools.d.ts +1 -0
- package/dist/meta-tools.d.ts.map +1 -1
- package/dist/meta-tools.js +412 -12
- package/dist/meta-tools.js.map +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +1 -1
- package/dist/tool-safety.d.ts +10 -0
- package/dist/tool-safety.d.ts.map +1 -0
- package/dist/tool-safety.js +12 -0
- package/dist/tool-safety.js.map +1 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +100 -1
- package/dist/validate.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -0
- package/documentation/auth.md +58 -0
- package/documentation/call-admission.md +7 -0
- package/documentation/code-first-exploration.md +292 -0
- package/documentation/code-mode.md +696 -0
- package/documentation/connector-guides.md +7 -0
- package/documentation/connectors.md +69 -0
- package/documentation/mcp-2026-07-28.md +46 -0
- package/documentation/meta-tools.md +185 -0
- package/documentation/operations.md +7 -0
- package/documentation/operator-ui.md +7 -0
- package/documentation/request-admission.md +7 -0
- package/documentation/storage-and-credentials.md +54 -0
- package/ethos.md +132 -0
- package/examples/node/README.md +53 -0
- package/examples/node/src/index.ts +73 -0
- package/examples/worker/README.md +160 -0
- package/examples/worker/src/cloudflare-kv.ts +43 -0
- package/examples/worker/src/d1-activity-row.ts +100 -0
- package/examples/worker/src/d1-activity.ts +144 -0
- package/examples/worker/src/index.ts +136 -0
- package/examples/worker/wrangler.jsonc +26 -0
- package/package.json +11 -1
- package/src/catalog-service.ts +181 -16
- package/src/catalog.ts +143 -12
- package/src/errors.ts +88 -1
- package/src/execute.ts +372 -96
- package/src/invocation.ts +45 -8
- package/src/meta-tools.ts +506 -11
- package/src/skills.ts +1 -1
- package/src/tool-safety.ts +15 -0
- package/src/validate.ts +128 -0
- package/src/version.ts +1 -1
- package/templates/node/.env.example +5 -0
- package/templates/node/AGENTS.md +19 -0
- package/templates/node/README.md +33 -0
- package/templates/node/package.json +23 -0
- package/templates/node/src/index.ts +43 -0
- package/templates/node/tsconfig.json +12 -0
package/src/validate.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Validator } from "@cfworker/json-schema";
|
|
2
2
|
import { ConnectorCallError } from "./errors.js";
|
|
3
|
+
import type {
|
|
4
|
+
ArgumentValidationDetails,
|
|
5
|
+
ArgumentValidationIssue,
|
|
6
|
+
} from "./errors.js";
|
|
7
|
+
import { MAX_ARGUMENT_VALIDATION_ISSUES } from "./errors.js";
|
|
3
8
|
import type { JsonSchema, Logger } from "./types.js";
|
|
4
9
|
|
|
5
10
|
export interface ValidateToolInputOptions {
|
|
@@ -42,6 +47,128 @@ export interface PrecompileValidatorOptions {
|
|
|
42
47
|
// breaking a working tool). A WeakMap so schemas belonging to a discarded
|
|
43
48
|
// connector are collectable, the same pattern compactSchema uses.
|
|
44
49
|
const validators = new WeakMap<JsonSchema, Validator | null>();
|
|
50
|
+
const REQUIRED_PROPERTY_RE =
|
|
51
|
+
/^Instance does not have required property "([^"]+)"\.$/;
|
|
52
|
+
|
|
53
|
+
interface ValidationUnit {
|
|
54
|
+
keyword: string;
|
|
55
|
+
keywordLocation: string;
|
|
56
|
+
instanceLocation: string;
|
|
57
|
+
error: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function decodePointerPart(value: string): string {
|
|
61
|
+
return value.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function encodePointerPart(value: string): string {
|
|
65
|
+
return value.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function pointerValue(value: unknown, pointer: string): unknown {
|
|
69
|
+
if (pointer === "#") return value;
|
|
70
|
+
if (!pointer.startsWith("#/")) return undefined;
|
|
71
|
+
let current = value;
|
|
72
|
+
for (const part of pointer.slice(2).split("/").map(decodePointerPart)) {
|
|
73
|
+
if (current === null || typeof current !== "object") return undefined;
|
|
74
|
+
current = (current as Record<string, unknown>)[part];
|
|
75
|
+
}
|
|
76
|
+
return current;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function argumentPath(location: string): string {
|
|
80
|
+
if (location === "#") return "/";
|
|
81
|
+
return location.startsWith("#") ? location.slice(1) || "/" : "/";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function expectedType(schema: JsonSchema, unit: ValidationUnit): string | undefined {
|
|
85
|
+
if (unit.keyword === "type") {
|
|
86
|
+
const value = pointerValue(schema, unit.keywordLocation);
|
|
87
|
+
if (typeof value === "string") return value;
|
|
88
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
89
|
+
return value.join(" | ");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (unit.keyword === "required") {
|
|
93
|
+
const missing = REQUIRED_PROPERTY_RE.exec(unit.error)?.[1];
|
|
94
|
+
if (!missing) return undefined;
|
|
95
|
+
const parentLocation = unit.keywordLocation.replace(/\/required$/, "");
|
|
96
|
+
const value = pointerValue(
|
|
97
|
+
schema,
|
|
98
|
+
`${parentLocation}/properties/${encodePointerPart(missing)}/type`,
|
|
99
|
+
);
|
|
100
|
+
if (typeof value === "string") return value;
|
|
101
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
102
|
+
return value.join(" | ");
|
|
103
|
+
}
|
|
104
|
+
return "present";
|
|
105
|
+
}
|
|
106
|
+
const fixed: Record<string, string> = {
|
|
107
|
+
additionalProperties: "no additional properties",
|
|
108
|
+
enum: "one of the declared values",
|
|
109
|
+
const: "the declared constant",
|
|
110
|
+
minLength: "the declared minimum length",
|
|
111
|
+
maxLength: "the declared maximum length",
|
|
112
|
+
minimum: "the declared minimum",
|
|
113
|
+
maximum: "the declared maximum",
|
|
114
|
+
pattern: "the declared string pattern",
|
|
115
|
+
};
|
|
116
|
+
return fixed[unit.keyword];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function validationDetails(
|
|
120
|
+
schema: JsonSchema,
|
|
121
|
+
units: ValidationUnit[],
|
|
122
|
+
): ArgumentValidationDetails {
|
|
123
|
+
const leafUnits = units.filter(
|
|
124
|
+
(unit) =>
|
|
125
|
+
![
|
|
126
|
+
"properties",
|
|
127
|
+
"items",
|
|
128
|
+
"allOf",
|
|
129
|
+
"anyOf",
|
|
130
|
+
"oneOf",
|
|
131
|
+
"if",
|
|
132
|
+
"not",
|
|
133
|
+
"patternProperties",
|
|
134
|
+
"additionalProperties",
|
|
135
|
+
].includes(unit.keyword),
|
|
136
|
+
);
|
|
137
|
+
const issues: ArgumentValidationIssue[] = [];
|
|
138
|
+
for (const unit of leafUnits) {
|
|
139
|
+
const missing =
|
|
140
|
+
unit.keyword === "required"
|
|
141
|
+
? REQUIRED_PROPERTY_RE.exec(unit.error)?.[1]
|
|
142
|
+
: undefined;
|
|
143
|
+
const path =
|
|
144
|
+
missing !== undefined
|
|
145
|
+
? `${argumentPath(unit.instanceLocation).replace(/\/$/, "")}/${encodePointerPart(missing)}`
|
|
146
|
+
: argumentPath(unit.instanceLocation);
|
|
147
|
+
const code = unit.keyword === "false" ? "additionalProperties" : unit.keyword;
|
|
148
|
+
const expected =
|
|
149
|
+
expectedType(schema, unit) ??
|
|
150
|
+
(code === "additionalProperties"
|
|
151
|
+
? "no additional properties"
|
|
152
|
+
: "the declared schema constraint");
|
|
153
|
+
const issue = { path, code, expected };
|
|
154
|
+
if (
|
|
155
|
+
!issues.some(
|
|
156
|
+
(existing) =>
|
|
157
|
+
existing.path === issue.path &&
|
|
158
|
+
existing.code === issue.code &&
|
|
159
|
+
existing.expected === issue.expected,
|
|
160
|
+
)
|
|
161
|
+
) {
|
|
162
|
+
issues.push(issue);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
issues: issues.slice(0, MAX_ARGUMENT_VALIDATION_ISSUES),
|
|
167
|
+
...(issues.length > MAX_ARGUMENT_VALIDATION_ISSUES
|
|
168
|
+
? { truncated: true as const }
|
|
169
|
+
: {}),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
45
172
|
|
|
46
173
|
function unevaluableSchema(address: string): ConnectorCallError {
|
|
47
174
|
return new ConnectorCallError(
|
|
@@ -127,6 +254,7 @@ export function validateToolInput(
|
|
|
127
254
|
return new ConnectorCallError(
|
|
128
255
|
"invalid_args",
|
|
129
256
|
`Invalid arguments for "${opts.address}": ${detail || "input does not match the tool's inputSchema"}`,
|
|
257
|
+
{ validation: validationDetails(schema, result.errors) },
|
|
130
258
|
);
|
|
131
259
|
}
|
|
132
260
|
return null;
|
package/src/version.ts
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Working on this Connecta deployment
|
|
2
|
+
|
|
3
|
+
This repository is deployment configuration, not a copy of Connecta itself.
|
|
4
|
+
|
|
5
|
+
- Edit `src/index.ts` for connectors, authentication, storage, and public URL.
|
|
6
|
+
- Keep `executor: quickJsExecutor()` for the prescribed seven-tool code-first
|
|
7
|
+
surface.
|
|
8
|
+
- Keep credentials in environment variables or an external secret store.
|
|
9
|
+
Never commit `.env`, `.connecta-state.json`, tokens, or credential values.
|
|
10
|
+
- Add application logic only inside deliberate `api()` connector handlers.
|
|
11
|
+
Do not copy or modify Connecta package internals here.
|
|
12
|
+
- Prefer `api()` when the agent must see an exact reviewed capability surface;
|
|
13
|
+
`remoteMcp()` follows the downstream server's evolving tool catalog.
|
|
14
|
+
- Run `npm run typecheck` after configuration changes. With the server running,
|
|
15
|
+
run `CONNECTA_TOKEN=... npm run doctor` before calling setup complete.
|
|
16
|
+
|
|
17
|
+
Do not add alternate entrypoints, policy layers, generated connector catalogs,
|
|
18
|
+
or runtime connector registration. Keep the deployment small enough to review
|
|
19
|
+
as configuration.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Connecta deployment
|
|
2
|
+
|
|
3
|
+
This is the prescribed small Node deployment. Install and run it:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install
|
|
7
|
+
CONNECTA_TOKEN=dev-token npm start
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Then point an MCP client at `http://localhost:8787/mcp` with
|
|
11
|
+
`Authorization: Bearer dev-token`.
|
|
12
|
+
|
|
13
|
+
## Deployment contract
|
|
14
|
+
|
|
15
|
+
- Edit `src/index.ts` for connectors, auth, storage, and the public URL.
|
|
16
|
+
- Keep `executor: quickJsExecutor()` for the seven-tool code-first surface.
|
|
17
|
+
- Keep secrets in environment variables or an external secret store.
|
|
18
|
+
- Add application code only inside deliberate `api()` connector handlers.
|
|
19
|
+
- Do not copy Connecta package internals into this deployment.
|
|
20
|
+
- `AGENTS.md` is the canonical convention file; `CLAUDE.md` points to it.
|
|
21
|
+
|
|
22
|
+
Verify a change with:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm run typecheck
|
|
26
|
+
# In another terminal, while npm start is running:
|
|
27
|
+
CONNECTA_TOKEN=dev-token npm run doctor
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Doctor checks health, the executor, and the exact prescribed seven-tool
|
|
31
|
+
model-facing surface by running a harmless sandbox program. It reads the bearer
|
|
32
|
+
from `CONNECTA_TOKEN`; it never accepts the secret as a command-line argument.
|
|
33
|
+
Remote URLs must use HTTPS.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "connecta-deployment",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.9.0"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"doctor": "connecta doctor",
|
|
11
|
+
"start": "tsx src/index.ts",
|
|
12
|
+
"typecheck": "tsc --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@zackbart/connecta": "0.10.3",
|
|
16
|
+
"quickjs-emscripten": "0.32.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^22.0.0",
|
|
20
|
+
"tsx": "^4.23.1",
|
|
21
|
+
"typescript": "^5.6.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prescribed Connecta deployment.
|
|
3
|
+
*
|
|
4
|
+
* Keep this file as deployment configuration: connectors, authentication,
|
|
5
|
+
* storage, and public origin. Add application logic only inside deliberate
|
|
6
|
+
* api() connector handlers.
|
|
7
|
+
*/
|
|
8
|
+
import { api, bearerToken, createConnecta } from "@zackbart/connecta";
|
|
9
|
+
import { fileStorage, listen } from "@zackbart/connecta/node";
|
|
10
|
+
import { quickJsExecutor } from "@zackbart/connecta/quickjs";
|
|
11
|
+
|
|
12
|
+
const token = process.env.CONNECTA_TOKEN;
|
|
13
|
+
if (!token) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
"CONNECTA_TOKEN is required. Refusing to start without inbound auth.",
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
const port = Number(process.env.PORT ?? 8787);
|
|
19
|
+
|
|
20
|
+
const connecta = createConnecta({
|
|
21
|
+
storage: fileStorage("./.connecta-state.json"),
|
|
22
|
+
auth: bearerToken(token, { subjectId: "operator" }),
|
|
23
|
+
publicUrl: `http://localhost:${port}`,
|
|
24
|
+
// Keep this for the prescribed seven-tool code-first surface.
|
|
25
|
+
executor: quickJsExecutor(),
|
|
26
|
+
connectors: [
|
|
27
|
+
api("time", {
|
|
28
|
+
description: "Time — current timestamp",
|
|
29
|
+
tools: [
|
|
30
|
+
{
|
|
31
|
+
name: "get_now",
|
|
32
|
+
description: "Return the current time as an ISO 8601 timestamp.",
|
|
33
|
+
inputSchema: { type: "object", properties: {} },
|
|
34
|
+
annotations: { readOnlyHint: true },
|
|
35
|
+
handler: async () => ({ now: new Date().toISOString() }),
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
listen(connecta, port);
|
|
43
|
+
console.log(`connecta listening on http://localhost:${port}/mcp`);
|