integrate-sdk 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,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Integrate SDK Contributors
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.
22
+
package/README.md ADDED
@@ -0,0 +1,639 @@
1
+ # Integrate SDK
2
+
3
+ A type-safe TypeScript SDK for building MCP (Model Context Protocol) clients with plugin-based OAuth provider configuration.
4
+
5
+ ## Features
6
+
7
+ - 🔌 **Plugin-Based Architecture** - Enable only the tools you need with a BetterAuth-inspired plugin pattern
8
+ - 🔒 **Type-Safe Configuration** - Full TypeScript support with IntelliSense for tools and configurations
9
+ - 🌊 **HTTP Streaming** - Real-time bidirectional communication via HTTP streaming with newline-delimited JSON (NDJSON)
10
+ - 🔐 **OAuth Support** - Built-in OAuth configuration for multiple providers
11
+ - 🛠️ **Extensible** - Easy to create custom plugins for any OAuth provider or tool set
12
+ - 📦 **Zero Dependencies** - Lightweight with no external runtime dependencies
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ bun add integrate-sdk
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ import { createMCPClient, githubPlugin, gmailPlugin } from 'integrate-sdk';
24
+
25
+ // Create a client with plugins
26
+ const client = createMCPClient({
27
+ serverUrl: 'http://localhost:3000/mcp',
28
+ plugins: [
29
+ githubPlugin({
30
+ clientId: process.env.GITHUB_CLIENT_ID!,
31
+ clientSecret: process.env.GITHUB_CLIENT_SECRET!,
32
+ scopes: ['repo', 'user'],
33
+ }),
34
+ gmailPlugin({
35
+ clientId: process.env.GMAIL_CLIENT_ID!,
36
+ clientSecret: process.env.GMAIL_CLIENT_SECRET!,
37
+ }),
38
+ ],
39
+ });
40
+
41
+ // Connect to the server
42
+ await client.connect();
43
+
44
+ // Call tools
45
+ const result = await client.callTool('github/createIssue', {
46
+ repo: 'owner/repo',
47
+ title: 'Bug report',
48
+ body: 'Description of the bug',
49
+ });
50
+
51
+ console.log('Issue created:', result);
52
+
53
+ // Disconnect when done
54
+ await client.disconnect();
55
+ ```
56
+
57
+ ## Built-in Plugins
58
+
59
+ ### GitHub Plugin
60
+
61
+ ```typescript
62
+ import { createMCPClient, githubPlugin } from 'integrate-sdk';
63
+
64
+ const client = createMCPClient({
65
+ serverUrl: 'http://localhost:3000/mcp',
66
+ plugins: [
67
+ githubPlugin({
68
+ clientId: process.env.GITHUB_CLIENT_ID!,
69
+ clientSecret: process.env.GITHUB_CLIENT_SECRET!,
70
+ scopes: ['repo', 'user', 'read:org'], // Optional, defaults to ['repo', 'user']
71
+ redirectUri: 'http://localhost:3000/callback', // Optional
72
+ }),
73
+ ],
74
+ });
75
+ ```
76
+
77
+ **Available Tools:**
78
+ - `github/createIssue`
79
+ - `github/listIssues`
80
+ - `github/getIssue`
81
+ - `github/updateIssue`
82
+ - `github/closeIssue`
83
+ - `github/createPullRequest`
84
+ - `github/listPullRequests`
85
+ - `github/getPullRequest`
86
+ - `github/mergePullRequest`
87
+ - `github/listRepositories`
88
+ - `github/getRepository`
89
+ - `github/createRepository`
90
+ - And more...
91
+
92
+ ### Gmail Plugin
93
+
94
+ ```typescript
95
+ import { createMCPClient, gmailPlugin } from 'integrate-sdk';
96
+
97
+ const client = createMCPClient({
98
+ serverUrl: 'http://localhost:3000/mcp',
99
+ plugins: [
100
+ gmailPlugin({
101
+ clientId: process.env.GMAIL_CLIENT_ID!,
102
+ clientSecret: process.env.GMAIL_CLIENT_SECRET!,
103
+ scopes: [ // Optional, defaults to common Gmail scopes
104
+ 'https://www.googleapis.com/auth/gmail.send',
105
+ 'https://www.googleapis.com/auth/gmail.readonly',
106
+ ],
107
+ }),
108
+ ],
109
+ });
110
+ ```
111
+
112
+ **Available Tools:**
113
+ - `gmail/sendEmail`
114
+ - `gmail/listEmails`
115
+ - `gmail/getEmail`
116
+ - `gmail/deleteEmail`
117
+ - `gmail/searchEmails`
118
+ - `gmail/markAsRead`
119
+ - `gmail/markAsUnread`
120
+ - `gmail/listLabels`
121
+ - `gmail/createLabel`
122
+ - And more...
123
+
124
+ ## Creating Custom Plugins
125
+
126
+ ### Using Generic OAuth Plugin
127
+
128
+ ```typescript
129
+ import { createMCPClient, genericOAuthPlugin } from 'integrate-sdk';
130
+
131
+ const slackPlugin = genericOAuthPlugin({
132
+ id: 'slack',
133
+ provider: 'slack',
134
+ clientId: process.env.SLACK_CLIENT_ID!,
135
+ clientSecret: process.env.SLACK_CLIENT_SECRET!,
136
+ scopes: ['chat:write', 'channels:read', 'users:read'],
137
+ tools: [
138
+ 'slack/sendMessage',
139
+ 'slack/listChannels',
140
+ 'slack/getChannel',
141
+ 'slack/inviteUser',
142
+ ],
143
+ redirectUri: 'http://localhost:3000/callback',
144
+ });
145
+
146
+ const client = createMCPClient({
147
+ serverUrl: 'http://localhost:3000/mcp',
148
+ plugins: [slackPlugin],
149
+ });
150
+ ```
151
+
152
+ ### Creating a Simple Plugin (No OAuth)
153
+
154
+ For tools that don't require OAuth:
155
+
156
+ ```typescript
157
+ import { createSimplePlugin } from 'integrate-sdk';
158
+
159
+ const mathPlugin = createSimplePlugin({
160
+ id: 'math',
161
+ tools: ['math/add', 'math/subtract', 'math/multiply', 'math/divide'],
162
+ onInit: async (client) => {
163
+ console.log('Math plugin initialized');
164
+ },
165
+ });
166
+ ```
167
+
168
+ ### Creating a Custom Plugin from Scratch
169
+
170
+ ```typescript
171
+ import type { MCPPlugin } from 'integrate-sdk';
172
+
173
+ export function customPlugin(config: CustomConfig): MCPPlugin {
174
+ return {
175
+ id: 'custom',
176
+ tools: ['custom/tool1', 'custom/tool2'],
177
+ oauth: {
178
+ provider: 'custom-provider',
179
+ clientId: config.clientId,
180
+ clientSecret: config.clientSecret,
181
+ scopes: config.scopes,
182
+ },
183
+
184
+ async onInit(client) {
185
+ // Called when plugin is initialized
186
+ console.log('Custom plugin initialized');
187
+ },
188
+
189
+ async onBeforeConnect(client) {
190
+ // Called before connecting to server
191
+ },
192
+
193
+ async onAfterConnect(client) {
194
+ // Called after successful connection
195
+ },
196
+
197
+ async onDisconnect(client) {
198
+ // Called when disconnecting
199
+ },
200
+ };
201
+ }
202
+ ```
203
+
204
+ ## Advanced Usage
205
+
206
+ ### Accessing OAuth Configurations
207
+
208
+ ```typescript
209
+ // Get OAuth config for a specific plugin
210
+ const githubOAuth = client.getOAuthConfig('github');
211
+ console.log('GitHub OAuth scopes:', githubOAuth?.scopes);
212
+
213
+ // Get all OAuth configs
214
+ const allConfigs = client.getAllOAuthConfigs();
215
+ for (const [pluginId, config] of allConfigs) {
216
+ console.log(`${pluginId}: ${config.provider}`);
217
+ }
218
+ ```
219
+
220
+ ### Listing Available Tools
221
+
222
+ ```typescript
223
+ await client.connect();
224
+
225
+ // Get all enabled tools (filtered by plugins)
226
+ const enabledTools = client.getEnabledTools();
227
+ console.log('Enabled tools:', enabledTools.map(t => t.name));
228
+
229
+ // Get all available tools from server
230
+ const allTools = client.getAvailableTools();
231
+ console.log('All tools:', allTools.map(t => t.name));
232
+
233
+ // Get a specific tool
234
+ const tool = client.getTool('github/createIssue');
235
+ console.log('Tool schema:', tool?.inputSchema);
236
+ ```
237
+
238
+ ### Handling Messages and Notifications
239
+
240
+ ```typescript
241
+ // Listen for server messages and notifications
242
+ const unsubscribe = client.onMessage((message) => {
243
+ console.log('Received message:', message);
244
+ });
245
+
246
+ // Unsubscribe when done
247
+ unsubscribe();
248
+ ```
249
+
250
+ ### Error Handling
251
+
252
+ ```typescript
253
+ try {
254
+ await client.connect();
255
+ const result = await client.callTool('github/createIssue', {
256
+ repo: 'owner/repo',
257
+ title: 'Bug report',
258
+ });
259
+ } catch (error) {
260
+ if (error.message.includes('not enabled')) {
261
+ console.error('Tool is not enabled. Add the appropriate plugin.');
262
+ } else if (error.message.includes('not available')) {
263
+ console.error('Tool is not available on the server.');
264
+ } else {
265
+ console.error('Unexpected error:', error);
266
+ }
267
+ }
268
+ ```
269
+
270
+ ### Custom Headers and Timeouts
271
+
272
+ ```typescript
273
+ const client = createMCPClient({
274
+ serverUrl: 'http://localhost:3000/mcp',
275
+ plugins: [/* ... */],
276
+
277
+ // Custom headers
278
+ headers: {
279
+ 'Authorization': 'Bearer token',
280
+ 'X-Custom-Header': 'value',
281
+ },
282
+
283
+ // Request timeout (default: 30000ms)
284
+ timeout: 60000,
285
+
286
+ // Custom client info
287
+ clientInfo: {
288
+ name: 'my-app',
289
+ version: '1.0.0',
290
+ },
291
+ });
292
+ ```
293
+
294
+ ## API Reference
295
+
296
+ ### `createMCPClient(config)`
297
+
298
+ Creates a new MCP client instance.
299
+
300
+ **Parameters:**
301
+ - `config.serverUrl` (string): URL of the MCP server
302
+ - `config.plugins` (MCPPlugin[]): Array of plugins to enable
303
+ - `config.headers` (object, optional): Custom HTTP headers
304
+ - `config.timeout` (number, optional): Request timeout in milliseconds
305
+ - `config.clientInfo` (object, optional): Client name and version
306
+
307
+ **Returns:** `MCPClient` instance
308
+
309
+ ### `MCPClient` Methods
310
+
311
+ - `connect()`: Connect to the MCP server
312
+ - `disconnect()`: Disconnect from the server
313
+ - `callTool(name, args)`: Invoke a tool by name
314
+ - `getTool(name)`: Get tool definition by name
315
+ - `getEnabledTools()`: Get all enabled tools
316
+ - `getAvailableTools()`: Get all available tools
317
+ - `getOAuthConfig(pluginId)`: Get OAuth config for a plugin
318
+ - `getAllOAuthConfigs()`: Get all OAuth configurations
319
+ - `onMessage(handler)`: Register a message handler
320
+ - `isConnected()`: Check if connected
321
+ - `isInitialized()`: Check if initialized
322
+
323
+ ## Architecture
324
+
325
+ The SDK is built with a modular architecture:
326
+
327
+ ```
328
+ integrate-sdk/
329
+ ├── src/
330
+ │ ├── client.ts # Main MCPClient class
331
+ │ ├── index.ts # Public exports
332
+ │ ├── config/
333
+ │ │ └── types.ts # Configuration types
334
+ │ ├── transport/
335
+ │ │ └── http-stream.ts # HTTP streaming transport (NDJSON)
336
+ │ ├── protocol/
337
+ │ │ ├── messages.ts # MCP message types
338
+ │ │ └── jsonrpc.ts # JSON-RPC implementation
339
+ │ └── plugins/
340
+ │ ├── types.ts # Plugin interface
341
+ │ ├── github.ts # GitHub plugin
342
+ │ ├── gmail.ts # Gmail plugin
343
+ │ └── generic.ts # Generic OAuth plugin
344
+ ```
345
+
346
+ **Transport Layer:**
347
+ The SDK uses HTTP streaming with newline-delimited JSON (NDJSON) for bidirectional communication:
348
+ - Single persistent HTTP connection
349
+ - Messages sent as JSON followed by newline (`\n`)
350
+ - Automatic heartbeat to keep connection alive
351
+ - Compatible with MCP's `StreamableHTTPServer`
352
+
353
+ ## MCP Server Requirements
354
+
355
+ Your MCP server should implement HTTP streaming transport compatible with MCP's `StreamableHTTPServer`:
356
+
357
+ - A single streaming endpoint (e.g., `POST /api/v1/mcp`) that:
358
+ - Accepts HTTP POST with streaming request body (NDJSON format)
359
+ - Returns streaming response body (NDJSON format)
360
+ - Supports bidirectional communication over a single persistent connection
361
+ - Messages are newline-delimited JSON (one JSON object per line)
362
+
363
+ And support these MCP protocol methods:
364
+ - `initialize` - Initialize the protocol connection
365
+ - `tools/list` - List available tools
366
+ - `tools/call` - Invoke a tool
367
+
368
+ **Example Go server setup:**
369
+ ```go
370
+ httpServer := server.NewStreamableHTTPServer(s,
371
+ server.WithEndpointPath("/api/v1/mcp"),
372
+ server.WithHeartbeatInterval(30*time.Second),
373
+ server.WithStateLess(false),
374
+ )
375
+ ```
376
+
377
+ ## TypeScript Support
378
+
379
+ The SDK is built with TypeScript and provides full type safety:
380
+
381
+ ```typescript
382
+ import { createMCPClient, githubPlugin } from 'integrate-sdk';
383
+ import type { MCPToolCallResponse } from 'integrate-sdk';
384
+
385
+ const client = createMCPClient({
386
+ serverUrl: 'http://localhost:3000/mcp',
387
+ plugins: [
388
+ githubPlugin({
389
+ clientId: process.env.GITHUB_CLIENT_ID!,
390
+ clientSecret: process.env.GITHUB_CLIENT_SECRET!,
391
+ }),
392
+ ],
393
+ });
394
+
395
+ // Full type inference and IntelliSense support
396
+ await client.connect();
397
+ const result: MCPToolCallResponse = await client.callTool('github/createIssue', {
398
+ repo: 'owner/repo',
399
+ title: 'Bug report',
400
+ });
401
+ ```
402
+
403
+ # Test Suite
404
+
405
+ Comprehensive test suite for the Integrate SDK.
406
+
407
+ ## Test Structure
408
+
409
+ ```
410
+ tests/
411
+ ├── protocol/ # Protocol and JSON-RPC tests
412
+ │ └── jsonrpc.test.ts
413
+ ├── plugins/ # Plugin system tests
414
+ │ └── plugin-system.test.ts
415
+ ├── client/ # Client functionality tests
416
+ │ └── client.test.ts
417
+ ├── integration/ # Integration tests with mock server
418
+ │ ├── mock-server.ts
419
+ │ └── integration.test.ts
420
+ ├── setup.ts # Test setup and utilities
421
+ └── README.md # This file
422
+ ```
423
+
424
+ ## Running Tests
425
+
426
+ ### All Tests
427
+ ```bash
428
+ bun test
429
+ ```
430
+
431
+ ### Unit Tests Only
432
+ ```bash
433
+ bun run test:unit
434
+ ```
435
+
436
+ ### Integration Tests Only
437
+ ```bash
438
+ bun run test:integration
439
+ ```
440
+
441
+ ### Watch Mode
442
+ ```bash
443
+ bun run test:watch
444
+ ```
445
+
446
+ ### With Coverage
447
+ ```bash
448
+ bun run test:coverage
449
+ ```
450
+
451
+ ## Test Categories
452
+
453
+ ### 1. Protocol Tests (`tests/protocol/`)
454
+ Tests for JSON-RPC 2.0 protocol implementation:
455
+ - Request/response formatting
456
+ - Notification handling
457
+ - Error responses
458
+ - Message parsing and serialization
459
+ - ID generation
460
+
461
+ ### 2. Plugin System Tests (`tests/plugins/`)
462
+ Tests for the plugin architecture:
463
+ - GitHub plugin configuration
464
+ - Gmail plugin configuration
465
+ - Generic OAuth plugin creation
466
+ - Simple plugin creation
467
+ - OAuth config type guards
468
+ - Plugin lifecycle hooks
469
+
470
+ ### 3. Client Tests (`tests/client/`)
471
+ Tests for the main MCP client:
472
+ - Client creation and configuration
473
+ - Plugin initialization
474
+ - OAuth configuration management
475
+ - Tool management
476
+ - Connection state tracking
477
+ - Error handling
478
+ - Message handlers
479
+
480
+ ### 4. Integration Tests (`tests/integration/`)
481
+ End-to-end tests with a mock MCP server:
482
+ - Connection establishment
483
+ - Tool discovery
484
+ - Tool filtering by plugins
485
+ - Tool invocation
486
+ - Plugin lifecycle hooks
487
+ - Concurrent requests
488
+ - Error scenarios
489
+ - Connection timeout
490
+
491
+ ## Mock Server
492
+
493
+ The integration tests use a mock MCP server that:
494
+ - Implements HTTP streaming with NDJSON
495
+ - Supports `initialize`, `tools/list`, and `tools/call` methods
496
+ - Returns configurable tools
497
+ - Handles heartbeat/ping messages
498
+ - Runs on a random port to avoid conflicts
499
+
500
+ Example usage:
501
+ ```typescript
502
+ import { MockMCPServer } from './tests/integration/mock-server';
503
+
504
+ const server = new MockMCPServer({
505
+ port: 3456,
506
+ tools: [
507
+ {
508
+ name: 'test/echo',
509
+ description: 'Echo test tool',
510
+ inputSchema: { /* ... */ }
511
+ }
512
+ ]
513
+ });
514
+
515
+ await server.start();
516
+ // Run tests...
517
+ await server.stop();
518
+ ```
519
+
520
+ ## Writing New Tests
521
+
522
+ ### Unit Test Example
523
+
524
+ ```typescript
525
+ import { describe, test, expect } from "bun:test";
526
+ import { myFunction } from "../../src/module.js";
527
+
528
+ describe("My Module", () => {
529
+ test("does something correctly", () => {
530
+ const result = myFunction("input");
531
+ expect(result).toBe("expected output");
532
+ });
533
+ });
534
+ ```
535
+
536
+ ### Integration Test Example
537
+
538
+ ```typescript
539
+ import { describe, test, expect, beforeAll, afterAll } from "bun:test";
540
+ import { createMCPClient } from "../../src/client.js";
541
+ import { MockMCPServer } from "./mock-server.js";
542
+
543
+ describe("Integration Test", () => {
544
+ let server: MockMCPServer;
545
+
546
+ beforeAll(async () => {
547
+ server = new MockMCPServer({ port: 3456 });
548
+ await server.start();
549
+ });
550
+
551
+ afterAll(async () => {
552
+ await server.stop();
553
+ });
554
+
555
+ test("connects and calls tool", async () => {
556
+ const client = createMCPClient({
557
+ serverUrl: server.getUrl(),
558
+ plugins: [/* ... */],
559
+ });
560
+
561
+ await client.connect();
562
+ const result = await client.callTool("test/tool");
563
+ expect(result).toBeDefined();
564
+ await client.disconnect();
565
+ });
566
+ });
567
+ ```
568
+
569
+ ## Test Coverage
570
+
571
+ The test suite covers:
572
+ - ✅ JSON-RPC protocol implementation
573
+ - ✅ Plugin system and configuration
574
+ - ✅ Client initialization and lifecycle
575
+ - ✅ Tool discovery and filtering
576
+ - ✅ Tool invocation
577
+ - ✅ OAuth configuration management
578
+ - ✅ Error handling
579
+ - ✅ Connection management
580
+ - ✅ Concurrent requests
581
+ - ✅ Plugin lifecycle hooks
582
+
583
+ ## Debugging Tests
584
+
585
+ Run tests with debug output:
586
+ ```bash
587
+ DEBUG=1 bun test
588
+ ```
589
+
590
+ Run specific test file:
591
+ ```bash
592
+ bun test tests/protocol/jsonrpc.test.ts
593
+ ```
594
+
595
+ Run specific test:
596
+ ```bash
597
+ bun test -t "creates valid JSON-RPC request"
598
+ ```
599
+
600
+ ## Continuous Integration
601
+
602
+ Tests run automatically on:
603
+ - Push to `main` or `develop` branches
604
+ - Pull requests to `main` or `develop`
605
+
606
+ The CI pipeline runs:
607
+ 1. Type checking
608
+ 2. Unit tests
609
+ 3. Integration tests
610
+ 4. Build verification
611
+
612
+ See `.github/workflows/test.yml` for details.
613
+
614
+ ## Common Issues
615
+
616
+ ### Port Already in Use
617
+ Integration tests use port 3456. If this conflicts, modify `MockMCPServer` constructor.
618
+
619
+ ### Test Timeouts
620
+ Integration tests have 10s timeout. Increase if needed:
621
+ ```typescript
622
+ test("my test", async () => {
623
+ // test code
624
+ }, 20000); // 20 second timeout
625
+ ```
626
+
627
+ ### Console Logs
628
+ Console logs are suppressed during tests unless `DEBUG=1` is set.
629
+
630
+ ## Contributing
631
+
632
+ When adding new features:
633
+ 1. Write unit tests for individual components
634
+ 2. Write integration tests for end-to-end flows
635
+ 3. Ensure all tests pass before submitting PR
636
+ 4. Maintain test coverage above 80%
637
+
638
+
639
+