@zackbart/connecta 0.18.1 → 0.18.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/CHANGELOG.md +80 -0
- package/README.md +4 -0
- package/dist/catalog-service.d.ts +4 -0
- package/dist/catalog-service.js +22 -6
- package/dist/connectors/remote-mcp.d.ts +49 -2
- package/dist/connectors/remote-mcp.js +302 -7
- package/dist/invocation.js +9 -3
- package/dist/providers/linear.d.ts +7 -1
- package/dist/providers/linear.js +12 -2
- package/dist/providers/mixpanel.d.ts +5 -1
- package/dist/providers/mixpanel.js +13 -2
- package/dist/providers/revenuecat.d.ts +3 -1
- package/dist/providers/revenuecat.js +12 -3
- package/dist/providers/stripe.d.ts +9 -3
- package/dist/providers/stripe.js +24 -5
- package/dist/registry.d.ts +7 -0
- package/dist/registry.js +9 -0
- package/dist/result-shapes.d.ts +13 -0
- package/dist/result-shapes.js +331 -0
- package/dist/skills.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +5 -2
- package/documentation/code-mode.md +6 -6
- package/documentation/connectors.md +35 -0
- package/documentation/linear.md +25 -4
- package/documentation/meta-tools.md +22 -3
- package/documentation/mixpanel.md +19 -0
- package/documentation/operations.md +3 -1
- package/documentation/provider-conventions.md +37 -21
- package/documentation/revenuecat.md +23 -1
- package/documentation/storage-and-credentials.md +55 -0
- package/documentation/stripe.md +22 -2
- package/documentation/upgrading.md +32 -4
- package/ethos.md +3 -3
- package/examples/worker/src/index.ts +5 -0
- package/package.json +1 -1
- package/templates/node/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,86 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this package are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.18.3 — 2026-08-25
|
|
6
|
+
|
|
7
|
+
This change gives code mode memory where downstream MCP catalogs are usually
|
|
8
|
+
silent: after a successful call with no declared output schema, Connecta keeps
|
|
9
|
+
only the result's field names and broad JSON types and shows that open shape on
|
|
10
|
+
later discovery. Nothing breaks, no deployment option changes, and providers
|
|
11
|
+
that already declare outputs are untouched. The bounded cache lives only in the
|
|
12
|
+
current process or Worker isolate and forgets each shape after 24 hours.
|
|
13
|
+
Discovery still never executes a tool, and
|
|
14
|
+
the new `outputSchemaSource: "observed"` marker is the warning label that keeps
|
|
15
|
+
one or several real results from masquerading as a provider contract.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Passive observed output schemas.** Successful explicitly read-only calls
|
|
20
|
+
whose provider declared no `outputSchema` infer and merge an open
|
|
21
|
+
optional-field schema of names and broad JSON types. The inference retains no
|
|
22
|
+
arguments, scalar values, raw results, code, credentials, or errors. Property
|
|
23
|
+
names may be user-authored. It bounds depth, breadth, names, nodes, definition
|
|
24
|
+
size, and schema bytes; keeps at most 256 runtime entries; ties each entry to
|
|
25
|
+
the exact tool definition; and expires it after 24 hours.
|
|
26
|
+
Search and describe return it with `outputSchemaSource: "observed"`; a
|
|
27
|
+
declared schema always wins. Observation is synchronous, storage-free, and
|
|
28
|
+
unable to fail the call. The design follows new warm-cache evidence and two
|
|
29
|
+
live deployment audits: BePresent had 246/378 tools without output schemas,
|
|
30
|
+
while OneMany's maintained connectors declared all 90 (#442).
|
|
31
|
+
|
|
32
|
+
## 0.18.2 — 2026-08-18
|
|
33
|
+
|
|
34
|
+
This patch closes the gap the RevenueCat rollout exposed on the same day 0.18.1
|
|
35
|
+
shipped: a hosted-MCP connection could authenticate with OAuth from the
|
|
36
|
+
Connections page or with a header literal baked into the deployment file, but
|
|
37
|
+
never with a key an operator pastes on `/credentials` the way every `api()`
|
|
38
|
+
connector already can. Now it can. Nothing breaks, no constructor changes, and a
|
|
39
|
+
deployment that keeps its static keys in runtime secrets can ignore this release.
|
|
40
|
+
Two things are worth reading before adopting the new shape: the operator vault
|
|
41
|
+
(`credentials.encryptionKey`) must be configured, and a key pasted with a
|
|
42
|
+
wrapped newline is refused before it is framed rather than echoed back by the
|
|
43
|
+
runtime that rejects it.
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **`auth: { type: "credential" }` for `remoteMcp()` and every maintained
|
|
48
|
+
hosted connection.** The connector declares an operator credential slot on
|
|
49
|
+
`/credentials` (label and guidance from the provider, overridable), reads the
|
|
50
|
+
stored value on every request before trusting a cached client, and frames it
|
|
51
|
+
as `Authorization: Bearer <value>` by default — `header` and `scheme` are
|
|
52
|
+
configurable, `scheme: null` sends the value bare, and a scheme ending in
|
|
53
|
+
`Basic` base64-encodes it, which is how Mixpanel's documented
|
|
54
|
+
`Bearer Basic <base64(user:secret)>` is spelled. A missing or empty value is
|
|
55
|
+
`auth_required`, and `authorize_connector` returns the operator handoff to
|
|
56
|
+
`/credentials`; a deployment without a vault warns at construction and answers
|
|
57
|
+
`recovery: "unavailable"` at use. Rotation on `/credentials` takes effect on
|
|
58
|
+
the next call: a SHA-256 digest of the connected value is compared per
|
|
59
|
+
request (including against an in-flight connect) and a differing digest
|
|
60
|
+
closes the old client. The `/credentials` Test action connects with the
|
|
61
|
+
candidate and counts the catalog, and only when an operator presses it — the
|
|
62
|
+
#179 refusal of proactive probing stands, now written into P10. Provider
|
|
63
|
+
defaults: Stripe (requires `mode`, refuses `connectedAccount`), Linear
|
|
64
|
+
(Bearer, per Linear's MCP docs), Mixpanel (`Bearer Basic`, service account),
|
|
65
|
+
RevenueCat (single-project branch, "API v2 secret key") (#439).
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- **A stored credential never reaches an agent or operator surface, even
|
|
70
|
+
malformed.** The value is refused before framing if it carries a control
|
|
71
|
+
character (the wrapped-newline paste), with a message that names the problem
|
|
72
|
+
and not the value; behind that, any error whose message or `cause` chain
|
|
73
|
+
quotes the raw or framed value is replaced whole rather than redacted. Both
|
|
74
|
+
layers are tested independently (#439).
|
|
75
|
+
|
|
76
|
+
- **Provider conventions P9 and P10 say what is now true.** P9 names both
|
|
77
|
+
headless shapes and requires the framing to match the provider's published
|
|
78
|
+
MCP contract; P10 is retitled to allow an operator-requested credential test
|
|
79
|
+
while forbidding any unasked probe (#439).
|
|
80
|
+
|
|
81
|
+
- **Linear's headers example uses `Bearer`.** Linear's MCP server documents
|
|
82
|
+
`Authorization: Bearer <token>` for API keys; the bare form is its GraphQL
|
|
83
|
+
convention. Existing `headers` connectors are untouched (#439).
|
|
84
|
+
|
|
5
85
|
## 0.18.1 — 2026-08-18
|
|
6
86
|
|
|
7
87
|
This patch is the response to one long investigation run against a live
|
package/README.md
CHANGED
|
@@ -67,6 +67,10 @@ Fifty issues in, one small object out. Your context window notices.
|
|
|
67
67
|
classifications, imported one at a time.
|
|
68
68
|
- **Let the agent work in code.** Search, chain, filter, join, and reduce
|
|
69
69
|
inside the sandbox instead of round-tripping every call through the model.
|
|
70
|
+
- **Teach undeclared result shapes by using them.** Successful read-only calls
|
|
71
|
+
retain field names and broad types in bounded runtime memory, never scalar
|
|
72
|
+
values, so later programs can project a remote MCP result its provider never
|
|
73
|
+
documented.
|
|
70
74
|
- **Keep writes deliberate.** Only tools marked read-only run in a program.
|
|
71
75
|
Everything else is a separate, visible call your client can gate.
|
|
72
76
|
- **Run it where you like.** Node, a Docker container, or a Cloudflare Worker,
|
|
@@ -49,6 +49,7 @@ interface CatalogSearchEntry {
|
|
|
49
49
|
description?: string;
|
|
50
50
|
inputSchema?: unknown;
|
|
51
51
|
outputSchema?: unknown;
|
|
52
|
+
outputSchemaSource?: "observed";
|
|
52
53
|
inputSchemaTruncated?: true;
|
|
53
54
|
outputSchemaTruncated?: true;
|
|
54
55
|
inputKeys?: string[];
|
|
@@ -112,6 +113,7 @@ export interface CatalogDescription {
|
|
|
112
113
|
guideRequiredReasons?: GuideRequiredReason[];
|
|
113
114
|
inputSchema?: unknown;
|
|
114
115
|
outputSchema?: unknown;
|
|
116
|
+
outputSchemaSource?: "observed";
|
|
115
117
|
annotations?: ToolDef["annotations"];
|
|
116
118
|
error?: string;
|
|
117
119
|
errorDetails?: CatalogDescriptionFailureDetail;
|
|
@@ -174,6 +176,7 @@ export declare class CatalogService {
|
|
|
174
176
|
}, purpose: string): NonNullable<CallErrorDetails["nextAction"]>;
|
|
175
177
|
loadConnector(id: string, callOptions?: ConnectorOperationOptions): Promise<ToolDef[]>;
|
|
176
178
|
private loadForDiscovery;
|
|
179
|
+
private outputSchema;
|
|
177
180
|
resolveTool(address: string, callOptions?: ConnectorOperationOptions): Promise<CatalogResolution>;
|
|
178
181
|
/**
|
|
179
182
|
* Resolve the JavaScript-safe property used by a lazy code-mode namespace
|
|
@@ -242,6 +245,7 @@ export declare function flatSearchResult(page: CatalogSearchPage): {
|
|
|
242
245
|
description?: string;
|
|
243
246
|
inputSchema?: unknown;
|
|
244
247
|
outputSchema?: unknown;
|
|
248
|
+
outputSchemaSource?: "observed";
|
|
245
249
|
inputSchemaTruncated?: true;
|
|
246
250
|
outputSchemaTruncated?: true;
|
|
247
251
|
inputKeys?: string[];
|
package/dist/catalog-service.js
CHANGED
|
@@ -266,6 +266,14 @@ export class CatalogService {
|
|
|
266
266
|
timeoutMs: this.probeTimeoutMs,
|
|
267
267
|
}), this.probeTimeoutMs, label);
|
|
268
268
|
}
|
|
269
|
+
outputSchema(connectorId, tool) {
|
|
270
|
+
if (tool.outputSchema)
|
|
271
|
+
return { schema: tool.outputSchema };
|
|
272
|
+
const observed = this.registry.observedOutputSchema(connectorId, tool);
|
|
273
|
+
return observed
|
|
274
|
+
? { schema: observed, source: "observed" }
|
|
275
|
+
: {};
|
|
276
|
+
}
|
|
269
277
|
async resolveTool(address, callOptions = {}) {
|
|
270
278
|
const resolved = this.registry.resolveAddress(address);
|
|
271
279
|
if (!resolved) {
|
|
@@ -487,15 +495,18 @@ export class CatalogService {
|
|
|
487
495
|
});
|
|
488
496
|
const pageMatches = matches.slice(offset, offset + limit);
|
|
489
497
|
const entries = pageMatches.map((match) => {
|
|
498
|
+
const output = args.includeSchemas
|
|
499
|
+
? this.outputSchema(match.connector.id, match.tool)
|
|
500
|
+
: {};
|
|
490
501
|
const input = match.tool.inputSchema ?? { type: "object" };
|
|
491
502
|
const renderedInput = args.includeSchemas
|
|
492
503
|
? renderSearchSchema(input, args.includeSchemas)
|
|
493
504
|
: undefined;
|
|
494
|
-
const renderedOutput = args.includeSchemas &&
|
|
495
|
-
? renderSearchSchema(
|
|
505
|
+
const renderedOutput = args.includeSchemas && output.schema
|
|
506
|
+
? renderSearchSchema(output.schema, args.includeSchemas)
|
|
496
507
|
: undefined;
|
|
497
508
|
const schemaKeys = args.includeSchemas && args.includeSchemaKeys
|
|
498
|
-
? schemaKeyMetadata(input,
|
|
509
|
+
? schemaKeyMetadata(input, output.schema)
|
|
499
510
|
: undefined;
|
|
500
511
|
const description = summarizeDiscoveryDescription(match.tool.description, args.fullDescriptions === true);
|
|
501
512
|
const requiredReasons = guideRequiredReasons(match.connector, match.tool, renderedInput?.truncated === true || renderedOutput?.truncated === true);
|
|
@@ -520,11 +531,14 @@ export class CatalogService {
|
|
|
520
531
|
...(renderedInput?.truncated
|
|
521
532
|
? { inputSchemaTruncated: true }
|
|
522
533
|
: {}),
|
|
523
|
-
...(args.includeSchemas &&
|
|
534
|
+
...(args.includeSchemas && output.schema
|
|
524
535
|
? {
|
|
525
536
|
outputSchema: renderedOutput?.schema,
|
|
526
537
|
}
|
|
527
538
|
: {}),
|
|
539
|
+
...(args.includeSchemas && output.source
|
|
540
|
+
? { outputSchemaSource: output.source }
|
|
541
|
+
: {}),
|
|
528
542
|
...(renderedOutput?.truncated
|
|
529
543
|
? { outputSchemaTruncated: true }
|
|
530
544
|
: {}),
|
|
@@ -813,6 +827,7 @@ export class CatalogService {
|
|
|
813
827
|
};
|
|
814
828
|
}
|
|
815
829
|
const input = tool.inputSchema ?? { type: "object" };
|
|
830
|
+
const output = this.outputSchema(addressResolution.connector.id, tool);
|
|
816
831
|
const description = summarizeDescription(tool.description, args.fullDescriptions === true);
|
|
817
832
|
const requiredReasons = guideRequiredReasons(addressResolution.connector, tool, false);
|
|
818
833
|
const guideSummary = connectorGuideSummary(addressResolution.connector);
|
|
@@ -833,11 +848,12 @@ export class CatalogService {
|
|
|
833
848
|
}
|
|
834
849
|
: {}),
|
|
835
850
|
inputSchema: renderSchema(input, format),
|
|
836
|
-
...(
|
|
851
|
+
...(output.schema
|
|
837
852
|
? {
|
|
838
|
-
outputSchema: renderSchema(
|
|
853
|
+
outputSchema: renderSchema(output.schema, format),
|
|
839
854
|
}
|
|
840
855
|
: {}),
|
|
856
|
+
...(output.source ? { outputSchemaSource: output.source } : {}),
|
|
841
857
|
...(tool.annotations ? { annotations: tool.annotations } : {}),
|
|
842
858
|
};
|
|
843
859
|
});
|
|
@@ -1,12 +1,58 @@
|
|
|
1
1
|
import type { FetchLike, Transport } from "@modelcontextprotocol/client";
|
|
2
2
|
import { ConnectorCallError } from "../errors.js";
|
|
3
|
-
import type { Connector, ConnectorCallAdmissionPolicy, ConnectorContext, ConnectorUsageGuide, Logger } from "../types.js";
|
|
3
|
+
import type { Connector, ConnectorCallAdmissionPolicy, ConnectorContext, ConnectorCredentialConfig, ConnectorUsageGuide, Logger } from "../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* A static downstream credential the operator supplies at `/credentials`
|
|
6
|
+
* rather than the deployment baking into its source.
|
|
7
|
+
*
|
|
8
|
+
* The connector, its endpoint, and the credential *slot* stay declared in
|
|
9
|
+
* code; only the secret arrives through the operator route, exactly as for
|
|
10
|
+
* `api()`. One reserved `value` field, deliberately: a header is assembled
|
|
11
|
+
* from a name, a framing scheme, and one secret, and anything that needs two
|
|
12
|
+
* secrets composed into one header is a provider integration, not a proxy
|
|
13
|
+
* config ([#439](https://github.com/zackbart/connecta/issues/439)).
|
|
14
|
+
*/
|
|
15
|
+
interface RemoteMcpCredentialAuth {
|
|
16
|
+
type: "credential";
|
|
17
|
+
/**
|
|
18
|
+
* Operator-facing slot description rendered on `/credentials`. Defaults to
|
|
19
|
+
* `{ label: "API key" }`; a maintained provider passes the name the provider
|
|
20
|
+
* itself uses. Named `fields` are refused — this shape reads the reserved
|
|
21
|
+
* `value` field only.
|
|
22
|
+
*/
|
|
23
|
+
credential?: ConnectorCredentialConfig;
|
|
24
|
+
/** Header the credential rides. Defaults to `Authorization`. */
|
|
25
|
+
header?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Framing token placed before the value. Defaults to `"Bearer"`. `null` (or
|
|
28
|
+
* an empty string) sends the stored value verbatim, for an endpoint that
|
|
29
|
+
* reads a bare key. A scheme whose last token is `Basic` declares
|
|
30
|
+
* HTTP Basic credentials: the stored `user:secret` is base64-encoded first,
|
|
31
|
+
* so `"Basic"` produces `Basic <base64>` and Mixpanel's documented
|
|
32
|
+
* `"Bearer Basic"` produces `Bearer Basic <base64>`.
|
|
33
|
+
*/
|
|
34
|
+
scheme?: string | null;
|
|
35
|
+
}
|
|
4
36
|
export type RemoteMcpAuth = {
|
|
5
37
|
type: "headers";
|
|
6
38
|
headers: Record<string, string>;
|
|
7
|
-
} | {
|
|
39
|
+
} | RemoteMcpCredentialAuth | {
|
|
8
40
|
type: "oauth";
|
|
9
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* Apply a maintained provider's slot copy and header framing to credential
|
|
44
|
+
* auth the deployment left bare.
|
|
45
|
+
*
|
|
46
|
+
* A provider knows what its own key is called and how the endpoint expects it
|
|
47
|
+
* framed; a deployment that states either one keeps its answer. Every other
|
|
48
|
+
* auth shape passes through untouched, so a provider can hand this its whole
|
|
49
|
+
* `auth` option without branching first.
|
|
50
|
+
*/
|
|
51
|
+
export declare function withCredentialDefaults(auth: RemoteMcpAuth, defaults: {
|
|
52
|
+
credential: ConnectorCredentialConfig;
|
|
53
|
+
/** Provider framing; omit to leave the `Bearer` default in place. */
|
|
54
|
+
scheme?: string | null;
|
|
55
|
+
}): RemoteMcpAuth;
|
|
10
56
|
export type RemoteMcpRedirectPolicy = "none" | "same-origin";
|
|
11
57
|
export interface RemoteMcpOptions {
|
|
12
58
|
url: string;
|
|
@@ -90,3 +136,4 @@ export declare function redirectSafeFetch(connectorId: string, policy?: RemoteMc
|
|
|
90
136
|
* server or hide other connectors).
|
|
91
137
|
*/
|
|
92
138
|
export declare function remoteMcp(id: string, opts: RemoteMcpOptions): Connector;
|
|
139
|
+
export {};
|