@gemstack/connectors 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Suleiman Shahbari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # @gemstack/connectors
2
+
3
+ The connector contract for GemStack AI orchestration. Define a tool connector to an external service (GitHub, Google Drive, ...) once with `defineConnector`, then compose any number of connectors into a single MCP server with `mountConnectors`.
4
+
5
+ Built on [`@gemstack/mcp`](../mcp). Framework-agnostic: the server it produces plugs into the same surface as any other `@gemstack/mcp` server (`Mcp.web` / `Mcp.local`, `McpTestClient`, the neutral HTTP handler).
6
+
7
+ > A connector only **declares** what it needs (its auth requirement) and **what it does** (its tools). It never reaches for env vars, OAuth, or a transport itself. The orchestrator that mounts it supplies credentials and chooses how to serve it. That split is what lets first-party and third-party connectors compose interchangeably.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm i @gemstack/connectors @gemstack/mcp zod
13
+ ```
14
+
15
+ ## Define a connector
16
+
17
+ ```ts
18
+ import { defineConnector } from '@gemstack/connectors'
19
+ import { z } from 'zod'
20
+
21
+ export default defineConnector({
22
+ id: 'notes', // lowercase, used to namespace this connector's tools
23
+ name: 'Notes',
24
+ auth: { type: 'none' }, // 'none' | 'pat' | 'oauth'
25
+ tools: [
26
+ {
27
+ name: 'list',
28
+ description: 'List all notes',
29
+ schema: z.object({}),
30
+ annotations: { readOnly: true },
31
+ handle: () => ['buy milk', 'ship connectors'],
32
+ },
33
+ {
34
+ name: 'get',
35
+ description: 'Get one note by index',
36
+ schema: z.object({ index: z.number() }),
37
+ annotations: { readOnly: true },
38
+ handle: (input, ctx) => {
39
+ // ctx.auth carries the credential the orchestrator resolved for 'notes'
40
+ return getNote(input.index)
41
+ },
42
+ },
43
+ ],
44
+ })
45
+ ```
46
+
47
+ A tool's `handle` may return a `string` (wrapped as text), any JSON-serializable value (wrapped as pretty JSON), or a full `McpToolResult` (use `McpResponse` from `@gemstack/mcp` for errors / images).
48
+
49
+ ## Mount connectors into a server
50
+
51
+ ```ts
52
+ import { mountConnectors } from '@gemstack/connectors'
53
+ import { Mcp } from '@gemstack/mcp'
54
+ import notes from './notes.js'
55
+ import github from '@gemstack/connector-github'
56
+
57
+ const Server = mountConnectors([notes, github], {
58
+ name: 'my-orchestrator',
59
+ // Resolve each connector's credential at call time. This is the seam that
60
+ // satisfies a connector's declared `auth`.
61
+ credentials: (id) => ({ token: process.env[`${id.toUpperCase()}_TOKEN`] }),
62
+ })
63
+
64
+ // The result is a standard @gemstack/mcp server class.
65
+ Mcp.web('/mcp/connectors', Server)
66
+ ```
67
+
68
+ Tools are namespaced by connector id, so `notes.list` is exposed as `notes_list` and never collides with another connector's `list`. Pass `namespace: 'none'` to keep names verbatim (you then own collision-avoidance).
69
+
70
+ ## Auth requirements
71
+
72
+ A connector declares one of:
73
+
74
+ | `auth.type` | Means | Credential the orchestrator provides |
75
+ |---|---|---|
76
+ | `none` | Public / local data | `{}` |
77
+ | `pat` | Personal access token / API key (`env` names a default var) | `{ token }` |
78
+ | `oauth` | OAuth 2.1 bearer (`scopes`, `authorizationServers`) | `{ token }` |
79
+
80
+ For `oauth`, protect the mounted endpoint with `@gemstack/mcp`'s `oauth2McpMiddleware` + `registerOAuth2Metadata` and feed the verified token through `credentials`.
81
+
82
+ ## Testing
83
+
84
+ ```ts
85
+ import { McpTestClient } from '@gemstack/mcp/testing'
86
+ import { mountConnectors } from '@gemstack/connectors'
87
+
88
+ const client = new McpTestClient(mountConnectors([notes]))
89
+ await client.listTools() // [{ name: 'notes_list', ... }, { name: 'notes_get', ... }]
90
+ await client.callTool('notes_get', { index: 0 })
91
+ ```
92
+
93
+ ## API
94
+
95
+ - `defineConnector(def): Connector` — validate + fill defaults.
96
+ - `mountConnectors(connectors, options?): ConnectorServerClass` — compose into one `@gemstack/mcp` server class.
97
+
98
+ See `examples/connectors-quickstart` in the repo for a runnable reference connector to copy from.
@@ -0,0 +1,15 @@
1
+ import type { Connector, ConnectorDefinition } from './types.js';
2
+ /**
3
+ * Define a tool connector to an external service. Validates the shape and fills
4
+ * defaults, returning a {@link Connector} ready to pass to `mountConnectors`.
5
+ *
6
+ * ```ts
7
+ * export default defineConnector({
8
+ * id: 'github',
9
+ * auth: { type: 'oauth', scopes: ['repo'] },
10
+ * tools: [{ name: 'list-issues', schema: ..., handle: async (input, ctx) => ... }],
11
+ * })
12
+ * ```
13
+ */
14
+ export declare function defineConnector(def: ConnectorDefinition): Connector;
15
+ //# sourceMappingURL=defineConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defineConnector.d.ts","sourceRoot":"","sources":["../src/defineConnector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAKhE;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,mBAAmB,GAAG,SAAS,CAwCnE"}
@@ -0,0 +1,50 @@
1
+ /** Connector ids and tool names share this charset so namespaced names stay MCP-safe. */
2
+ const ID_RE = /^[a-z][a-z0-9-]*$/;
3
+ /**
4
+ * Define a tool connector to an external service. Validates the shape and fills
5
+ * defaults, returning a {@link Connector} ready to pass to `mountConnectors`.
6
+ *
7
+ * ```ts
8
+ * export default defineConnector({
9
+ * id: 'github',
10
+ * auth: { type: 'oauth', scopes: ['repo'] },
11
+ * tools: [{ name: 'list-issues', schema: ..., handle: async (input, ctx) => ... }],
12
+ * })
13
+ * ```
14
+ */
15
+ export function defineConnector(def) {
16
+ if (!def || typeof def !== 'object') {
17
+ throw new TypeError('defineConnector: expected a connector definition object');
18
+ }
19
+ if (!ID_RE.test(def.id ?? '')) {
20
+ throw new Error(`defineConnector: invalid id ${JSON.stringify(def.id)} — use lowercase letters, digits, and "-" (must start with a letter)`);
21
+ }
22
+ if (!Array.isArray(def.tools) || def.tools.length === 0) {
23
+ throw new Error(`defineConnector("${def.id}"): at least one tool is required`);
24
+ }
25
+ const seen = new Set();
26
+ for (const tool of def.tools) {
27
+ if (!ID_RE.test(tool?.name ?? '')) {
28
+ throw new Error(`defineConnector("${def.id}"): invalid tool name ${JSON.stringify(tool?.name)} — use lowercase letters, digits, and "-"`);
29
+ }
30
+ if (seen.has(tool.name)) {
31
+ throw new Error(`defineConnector("${def.id}"): duplicate tool name "${tool.name}"`);
32
+ }
33
+ seen.add(tool.name);
34
+ if (typeof tool.handle !== 'function') {
35
+ throw new Error(`defineConnector("${def.id}"): tool "${tool.name}" is missing a handle() function`);
36
+ }
37
+ if (typeof tool.schema !== 'object' || tool.schema == null) {
38
+ throw new Error(`defineConnector("${def.id}"): tool "${tool.name}" is missing a Zod schema`);
39
+ }
40
+ }
41
+ return {
42
+ id: def.id,
43
+ name: def.name ?? def.id,
44
+ version: def.version ?? '1.0.0',
45
+ ...(def.instructions != null ? { instructions: def.instructions } : {}),
46
+ auth: def.auth ?? { type: 'none' },
47
+ tools: def.tools,
48
+ };
49
+ }
50
+ //# sourceMappingURL=defineConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defineConnector.js","sourceRoot":"","sources":["../src/defineConnector.ts"],"names":[],"mappings":"AAEA,yFAAyF;AACzF,MAAM,KAAK,GAAG,mBAAmB,CAAA;AAEjC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,GAAwB;IACtD,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,IAAI,SAAS,CAAC,yDAAyD,CAAC,CAAA;IAChF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,+BAA+B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,sEAAsE,CAC5H,CAAA;IACH,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,EAAE,mCAAmC,CAAC,CAAA;IAChF,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CACb,oBAAoB,GAAG,CAAC,EAAE,yBAAyB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,2CAA2C,CACzH,CAAA;QACH,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,EAAE,4BAA4B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACnB,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,EAAE,aAAa,IAAI,CAAC,IAAI,kCAAkC,CAAC,CAAA;QACrG,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,EAAE,aAAa,IAAI,CAAC,IAAI,2BAA2B,CAAC,CAAA;QAC9F,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE;QACxB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,OAAO;QAC/B,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;QAClC,KAAK,EAAE,GAAG,CAAC,KAAK;KACjB,CAAA;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { defineConnector } from './defineConnector.js';
2
+ export { mountConnectors } from './mountConnectors.js';
3
+ export type { ConnectorServerClass, MountOptions } from './mountConnectors.js';
4
+ export type { Connector, ConnectorDefinition, ConnectorTool, ConnectorToolAnnotations, ConnectorToolReturn, ConnectorAuth, ConnectorContext, Credential, } from './types.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAC9E,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,wBAAwB,EACxB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { defineConnector } from './defineConnector.js';
2
+ export { mountConnectors } from './mountConnectors.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,42 @@
1
+ import { McpServer } from '@gemstack/mcp';
2
+ import type { McpServerOptions } from '@gemstack/mcp';
3
+ import type { Connector, Credential } from './types.js';
4
+ /** A constructable MCP server, ready for `Mcp.web()` / `Mcp.local()` or `McpTestClient`. */
5
+ export type ConnectorServerClass = new (options?: McpServerOptions) => McpServer;
6
+ export interface MountOptions {
7
+ /** Server name advertised to clients. Default `"connectors"`. */
8
+ name?: string;
9
+ /** Server version. Default `"1.0.0"`. */
10
+ version?: string;
11
+ /** Server-level instructions surfaced to the agent. */
12
+ instructions?: string;
13
+ /**
14
+ * Resolve the credential for a connector at tool-call time. Called with the
15
+ * connector id before each tool runs; return `undefined` for connectors that
16
+ * need none. This is the seam the orchestrator implements to satisfy each
17
+ * connector's declared {@link Connector.auth}.
18
+ */
19
+ credentials?: (connectorId: string) => Credential | undefined | Promise<Credential | undefined>;
20
+ /**
21
+ * How tool names are disambiguated across connectors.
22
+ * - `'prefix'` (default): `"<connectorId>_<toolName>"`.
23
+ * - `'none'`: tool names kept verbatim (you must ensure they don't collide).
24
+ */
25
+ namespace?: 'prefix' | 'none';
26
+ }
27
+ /**
28
+ * Compose any number of connectors into a single MCP server class. Each
29
+ * connector's tools become MCP tools on one server, namespaced by connector id
30
+ * so names never collide. The returned class plugs straight into the
31
+ * @gemstack/mcp surface: register it with `Mcp.web(path, ServerClass)` /
32
+ * `Mcp.local(name, ServerClass)`, or drive it in tests with `McpTestClient`.
33
+ *
34
+ * ```ts
35
+ * const Server = mountConnectors([github, drive], {
36
+ * credentials: (id) => ({ token: process.env[`${id.toUpperCase()}_TOKEN`] }),
37
+ * })
38
+ * Mcp.web('/mcp/connectors', Server)
39
+ * ```
40
+ */
41
+ export declare function mountConnectors(connectors: Connector[], options?: MountOptions): ConnectorServerClass;
42
+ //# sourceMappingURL=mountConnectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mountConnectors.d.ts","sourceRoot":"","sources":["../src/mountConnectors.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAOV,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,gBAAgB,EAAgC,MAAM,eAAe,CAAA;AACnF,OAAO,KAAK,EAAE,SAAS,EAAwD,UAAU,EAAE,MAAM,YAAY,CAAA;AAE7G,4FAA4F;AAC5F,MAAM,MAAM,oBAAoB,GAAG,KAAK,OAAO,CAAC,EAAE,gBAAgB,KAAK,SAAS,CAAA;AAEhF,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;IAC/F;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,OAAO,GAAE,YAAiB,GAAG,oBAAoB,CA4BzG"}
@@ -0,0 +1,83 @@
1
+ import { McpServer, McpTool, McpResponse, IsReadOnly, IsDestructive, IsIdempotent, IsOpenWorld, } from '@gemstack/mcp';
2
+ /**
3
+ * Compose any number of connectors into a single MCP server class. Each
4
+ * connector's tools become MCP tools on one server, namespaced by connector id
5
+ * so names never collide. The returned class plugs straight into the
6
+ * @gemstack/mcp surface: register it with `Mcp.web(path, ServerClass)` /
7
+ * `Mcp.local(name, ServerClass)`, or drive it in tests with `McpTestClient`.
8
+ *
9
+ * ```ts
10
+ * const Server = mountConnectors([github, drive], {
11
+ * credentials: (id) => ({ token: process.env[`${id.toUpperCase()}_TOKEN`] }),
12
+ * })
13
+ * Mcp.web('/mcp/connectors', Server)
14
+ * ```
15
+ */
16
+ export function mountConnectors(connectors, options = {}) {
17
+ const namespace = options.namespace ?? 'prefix';
18
+ const toolClasses = [];
19
+ const seen = new Set();
20
+ for (const connector of connectors) {
21
+ for (const tool of connector.tools) {
22
+ const toolName = namespace === 'prefix' ? `${connector.id}_${tool.name}` : tool.name;
23
+ if (seen.has(toolName)) {
24
+ throw new Error(`mountConnectors: duplicate tool name "${toolName}" — two connectors expose the same tool (use namespace: 'prefix')`);
25
+ }
26
+ seen.add(toolName);
27
+ toolClasses.push(makeToolClass(connector, tool, toolName, options));
28
+ }
29
+ }
30
+ const name = options.name ?? 'connectors';
31
+ const version = options.version ?? '1.0.0';
32
+ const instructions = options.instructions;
33
+ return class ConnectorsServer extends McpServer {
34
+ tools = toolClasses;
35
+ metadata() {
36
+ return { name, version, ...(instructions != null ? { instructions } : {}) };
37
+ }
38
+ };
39
+ }
40
+ function makeToolClass(connector, tool, toolName, options) {
41
+ class ConnectorToolImpl extends McpTool {
42
+ name() {
43
+ return toolName;
44
+ }
45
+ description() {
46
+ return tool.description ?? '';
47
+ }
48
+ schema() {
49
+ return tool.schema;
50
+ }
51
+ async handle(input) {
52
+ const auth = (await options.credentials?.(connector.id)) ?? {};
53
+ const ctx = { connectorId: connector.id, auth };
54
+ return normalizeResult(await tool.handle(input, ctx));
55
+ }
56
+ }
57
+ if (tool.outputSchema) {
58
+ const outputSchema = tool.outputSchema;
59
+ ConnectorToolImpl.prototype.outputSchema = () => outputSchema;
60
+ }
61
+ const a = tool.annotations;
62
+ if (a?.readOnly)
63
+ IsReadOnly(true)(ConnectorToolImpl);
64
+ if (a?.destructive)
65
+ IsDestructive(true)(ConnectorToolImpl);
66
+ if (a?.idempotent)
67
+ IsIdempotent(true)(ConnectorToolImpl);
68
+ if (a?.openWorld)
69
+ IsOpenWorld(true)(ConnectorToolImpl);
70
+ return ConnectorToolImpl;
71
+ }
72
+ /** Wrap a connector handler's return into a {@link McpToolResult}. */
73
+ function normalizeResult(result) {
74
+ if (isToolResult(result))
75
+ return result;
76
+ if (typeof result === 'string')
77
+ return McpResponse.text(result);
78
+ return McpResponse.json(result);
79
+ }
80
+ function isToolResult(value) {
81
+ return !!value && typeof value === 'object' && Array.isArray(value.content);
82
+ }
83
+ //# sourceMappingURL=mountConnectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mountConnectors.js","sourceRoot":"","sources":["../src/mountConnectors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import type { McpToolResult, ZodLikeObject } from '@gemstack/mcp';
2
+ /**
3
+ * What credential a connector needs to reach its external service. The
4
+ * orchestrator reads this to know how to satisfy the connector, then hands a
5
+ * resolved {@link Credential} to each tool call. The connector only *declares*
6
+ * its requirement here; it never reaches for env vars or OAuth itself.
7
+ */
8
+ export type ConnectorAuth =
9
+ /** No credential needed (public data, local source). */
10
+ {
11
+ type: 'none';
12
+ }
13
+ /** A personal access token / API key. `env` names a default env var to read. */
14
+ | {
15
+ type: 'pat';
16
+ description?: string;
17
+ env?: string;
18
+ }
19
+ /** OAuth 2.1 bearer token. Mirrors the @gemstack/mcp OAuth protect options. */
20
+ | {
21
+ type: 'oauth';
22
+ scopes?: string[];
23
+ authorizationServers?: string[];
24
+ description?: string;
25
+ };
26
+ /**
27
+ * A credential resolved for one connector and handed to its tools at call time.
28
+ * `token` is the common case (PAT or bearer); extra fields carry anything else
29
+ * a connector's credential provider wants to thread through.
30
+ */
31
+ export interface Credential {
32
+ token?: string | undefined;
33
+ [key: string]: unknown;
34
+ }
35
+ /** Context passed to every connector tool handler. */
36
+ export interface ConnectorContext {
37
+ /** The id of the connector this tool belongs to. */
38
+ connectorId: string;
39
+ /** The credential resolved for this connector (`{}` when none was provided). */
40
+ auth: Credential;
41
+ }
42
+ /**
43
+ * What a tool handler may return:
44
+ * - a full {@link McpToolResult} (use `McpResponse` from @gemstack/mcp), or
45
+ * - a `string` (wrapped as a text result), or
46
+ * - any JSON-serializable value (wrapped as pretty-printed JSON text).
47
+ */
48
+ export type ConnectorToolReturn = McpToolResult | string | unknown;
49
+ /**
50
+ * Behavioural hints advertised to MCP clients. They mirror the MCP tool
51
+ * annotations and let agents reason about a tool before calling it — e.g. only
52
+ * auto-approve `readOnly` tools. Default (all unset) means a read-write,
53
+ * non-destructive, non-idempotent tool.
54
+ */
55
+ export interface ConnectorToolAnnotations {
56
+ /** The tool does not modify any state. */
57
+ readOnly?: boolean;
58
+ /** The tool may perform destructive updates (deletes, overwrites). */
59
+ destructive?: boolean;
60
+ /** Calling repeatedly with the same input has no additional effect. */
61
+ idempotent?: boolean;
62
+ /** The tool interacts with the open world (external network / services). */
63
+ openWorld?: boolean;
64
+ }
65
+ /** A single tool a connector exposes. */
66
+ export interface ConnectorTool<Input = Record<string, unknown>> {
67
+ /** Tool name, unique within the connector. Kept verbatim (namespaced at mount). */
68
+ name: string;
69
+ /** One-line description shown to the agent. */
70
+ description?: string;
71
+ /** Input schema — a Zod object (v3 or v4). */
72
+ schema: ZodLikeObject;
73
+ /** Optional output schema advertised to clients. */
74
+ outputSchema?: ZodLikeObject;
75
+ /** Optional behavioural hints. */
76
+ annotations?: ConnectorToolAnnotations;
77
+ /** Run the tool. Receives validated input and the connector {@link ConnectorContext}. */
78
+ handle: (input: Input, ctx: ConnectorContext) => ConnectorToolReturn | Promise<ConnectorToolReturn>;
79
+ }
80
+ /** The object passed to {@link defineConnector}. */
81
+ export interface ConnectorDefinition {
82
+ /** Stable, unique id (lowercase letters, digits, `-`). Used to namespace tools. */
83
+ id: string;
84
+ /** Human-readable name. Defaults to `id`. */
85
+ name?: string;
86
+ /** Connector version. Defaults to `1.0.0`. */
87
+ version?: string;
88
+ /** Optional instructions surfaced to the agent at the server level. */
89
+ instructions?: string;
90
+ /** Credential requirement. Defaults to `{ type: 'none' }`. */
91
+ auth?: ConnectorAuth;
92
+ /**
93
+ * The tools this connector exposes (at least one). Typed loosely so each tool
94
+ * may annotate its own `handle` input (e.g. `(input: { id: string }) => ...`);
95
+ * the Zod `schema` is the runtime source of truth.
96
+ */
97
+ tools: ConnectorTool<any>[];
98
+ }
99
+ /** A validated connector, as returned by {@link defineConnector}. */
100
+ export interface Connector {
101
+ id: string;
102
+ name: string;
103
+ version: string;
104
+ instructions?: string;
105
+ auth: ConnectorAuth;
106
+ tools: ConnectorTool<any>[];
107
+ }
108
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,aAAa;AACvB,wDAAwD;AACtD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,gFAAgF;GAC9E;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE;AACrD,+EAA+E;GAC7E;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/F;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAGzB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAA;IACnB,gFAAgF;IAChF,IAAI,EAAE,UAAU,CAAA;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAA;AAElE;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,yCAAyC;AACzC,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5D,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAA;IACZ,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8CAA8C;IAC9C,MAAM,EAAE,aAAa,CAAA;IACrB,oDAAoD;IACpD,YAAY,CAAC,EAAE,aAAa,CAAA;IAC5B,kCAAkC;IAClC,WAAW,CAAC,EAAE,wBAAwB,CAAA;IACtC,yFAAyF;IACzF,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,KAAK,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;CACpG;AAED,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,EAAE,EAAE,MAAM,CAAA;IACV,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB;;;;OAIG;IAEH,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAA;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,aAAa,CAAA;IAEnB,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAA;CAC5B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@gemstack/connectors",
3
+ "version": "0.1.0",
4
+ "description": "The connector contract for GemStack AI orchestration: define a tool connector to an external service (GitHub, Google Drive, ...) once with `defineConnector`, compose any number into a single MCP server with `mountConnectors`. Built on @gemstack/mcp; framework-agnostic.",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "connector",
9
+ "connectors",
10
+ "ai",
11
+ "agents",
12
+ "orchestration",
13
+ "tools",
14
+ "gemstack"
15
+ ],
16
+ "license": "MIT",
17
+ "homepage": "https://github.com/gemstack-land/gemstack/tree/main/packages/connectors#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/gemstack-land/gemstack/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/gemstack-land/gemstack",
24
+ "directory": "packages/connectors"
25
+ },
26
+ "type": "module",
27
+ "engines": {
28
+ "node": ">=22.12.0"
29
+ },
30
+ "files": [
31
+ "dist"
32
+ ],
33
+ "main": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
35
+ "exports": {
36
+ ".": {
37
+ "import": "./dist/index.js",
38
+ "types": "./dist/index.d.ts"
39
+ }
40
+ },
41
+ "dependencies": {
42
+ "reflect-metadata": "^0.2.0",
43
+ "@gemstack/mcp": "^0.2.1"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.0.0",
47
+ "typescript": "^5.4.0",
48
+ "zod": "^4.0.0"
49
+ },
50
+ "author": "Suleiman Shahbari",
51
+ "scripts": {
52
+ "build": "tsc -p tsconfig.build.json",
53
+ "dev": "tsc -p tsconfig.build.json --watch",
54
+ "typecheck": "tsc --noEmit",
55
+ "test": "tsc -p tsconfig.test.json && cd dist-test && node --test",
56
+ "clean": "rm -rf dist dist-test"
57
+ }
58
+ }