matimo 0.1.0-alpha.2 → 0.1.0-alpha.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.
Files changed (88) hide show
  1. package/README.md +80 -26
  2. package/dist/core/schema.d.ts +1 -1
  3. package/dist/core/schema.d.ts.map +1 -1
  4. package/dist/core/schema.js +8 -3
  5. package/dist/core/schema.js.map +1 -1
  6. package/dist/core/tool-loader.d.ts.map +1 -1
  7. package/dist/core/tool-loader.js +15 -4
  8. package/dist/core/tool-loader.js.map +1 -1
  9. package/dist/core/tool-registry.d.ts.map +1 -1
  10. package/dist/core/tool-registry.js +5 -1
  11. package/dist/core/tool-registry.js.map +1 -1
  12. package/dist/decorators/tool-decorator.d.ts.map +1 -1
  13. package/dist/decorators/tool-decorator.js +7 -4
  14. package/dist/decorators/tool-decorator.js.map +1 -1
  15. package/dist/encodings/parameter-encoding.d.ts.map +1 -1
  16. package/dist/encodings/parameter-encoding.js +9 -2
  17. package/dist/encodings/parameter-encoding.js.map +1 -1
  18. package/dist/executors/command-executor.d.ts.map +1 -1
  19. package/dist/executors/command-executor.js +5 -1
  20. package/dist/executors/command-executor.js.map +1 -1
  21. package/dist/executors/http-executor.d.ts.map +1 -1
  22. package/dist/executors/http-executor.js +5 -1
  23. package/dist/executors/http-executor.js.map +1 -1
  24. package/package.json +4 -8
  25. package/tools/calculator/calculator.ts +78 -0
  26. package/tools/calculator/definition.yaml +71 -0
  27. package/tools/echo-tool/definition.yaml +35 -0
  28. package/tools/examples/calculator.yaml +54 -0
  29. package/tools/examples/echo-tool.yaml +35 -0
  30. package/tools/examples/http-client.yaml +66 -0
  31. package/tools/github/definition.yaml +41 -0
  32. package/tools/gmail/README.md +1189 -0
  33. package/tools/gmail/create-draft/definition.yaml +99 -0
  34. package/tools/gmail/definition.yaml +49 -0
  35. package/tools/gmail/delete-message/definition.yaml +42 -0
  36. package/tools/gmail/get-message/definition.yaml +89 -0
  37. package/tools/gmail/list-messages/definition.yaml +84 -0
  38. package/tools/gmail/send-email/definition.yaml +95 -0
  39. package/tools/http-client/definition.yaml +73 -0
  40. package/tools/slack/README.md +200 -0
  41. package/tools/slack/assets/icon.svg +9 -0
  42. package/tools/slack/assets/logo-dark.svg +14 -0
  43. package/tools/slack/assets/logo-light.svg +14 -0
  44. package/tools/slack/assets/logo.svg +14 -0
  45. package/tools/slack/definition.yaml +54 -0
  46. package/tools/slack/get-user/definition.yaml +31 -0
  47. package/tools/slack/list-channels/definition.yaml +46 -0
  48. package/tools/slack/send-message/definition.yaml +30 -0
  49. package/tools/slack/slack_add_reaction/definition.yaml +45 -0
  50. package/tools/slack/slack_create_channel/definition.yaml +41 -0
  51. package/tools/slack/slack_get_channel_history/definition.yaml +58 -0
  52. package/tools/slack/slack_get_reactions/definition.yaml +36 -0
  53. package/tools/slack/slack_get_thread_replies/definition.yaml +45 -0
  54. package/tools/slack/slack_get_user_info/definition.yaml +32 -0
  55. package/tools/slack/slack_join_channel/definition.yaml +35 -0
  56. package/tools/slack/slack_reply_to_message/definition.yaml +49 -0
  57. package/tools/slack/slack_search_messages/definition.yaml +46 -0
  58. package/tools/slack/slack_send_channel_message/definition.yaml +34 -0
  59. package/tools/slack/slack_send_dm/definition.yaml +37 -0
  60. package/tools/slack/slack_set_channel_topic/definition.yaml +40 -0
  61. package/tools/slack/slack_upload_file/definition.yaml +152 -0
  62. package/docs/Gemfile +0 -5
  63. package/docs/RELEASES.md +0 -90
  64. package/docs/ROADMAP.md +0 -138
  65. package/docs/_config.yml +0 -27
  66. package/docs/api-reference/ERRORS.md +0 -445
  67. package/docs/api-reference/SDK.md +0 -582
  68. package/docs/api-reference/TYPES.md +0 -415
  69. package/docs/architecture/OAUTH.md +0 -1366
  70. package/docs/architecture/OVERVIEW.md +0 -564
  71. package/docs/assets/logo.png +0 -0
  72. package/docs/community/COMMIT_GUIDELINES.md +0 -552
  73. package/docs/framework-integrations/LANGCHAIN.md +0 -286
  74. package/docs/getting-started/QUICK_START.md +0 -212
  75. package/docs/getting-started/YOUR_FIRST_TOOL.md +0 -217
  76. package/docs/getting-started/installation.md +0 -124
  77. package/docs/index.md +0 -289
  78. package/docs/tool-development/DECORATOR_GUIDE.md +0 -633
  79. package/docs/tool-development/OAUTH_LINK.md +0 -5
  80. package/docs/tool-development/PROVIDER_CONFIGURATION.md +0 -458
  81. package/docs/tool-development/TESTING.md +0 -412
  82. package/docs/tool-development/TOOL_SPECIFICATION.md +0 -793
  83. package/docs/tool-development/YAML_TOOLS.md +0 -65
  84. package/docs/troubleshooting/FAQ.md +0 -391
  85. package/docs/user-guide/AUTHENTICATION.md +0 -255
  86. package/docs/user-guide/DEVELOPMENT_STANDARDS.md +0 -698
  87. package/docs/user-guide/SDK_PATTERNS.md +0 -316
  88. package/docs/user-guide/TOOL_DISCOVERY.md +0 -209
@@ -1,1366 +0,0 @@
1
- # Matimo OAuth2 Implementation Guide
2
-
3
- Complete reference for OAuth2 in Matimo: architecture, token injection, provider configuration, troubleshooting, and best practices.
4
-
5
- ## 📋 Table of Contents
6
-
7
- - [Overview](#overview)
8
- - [Architecture](#architecture)
9
- - [OAuth2 Flow](#oauth2-flow)
10
- - [Provider YAML Configuration](#provider-yaml-configuration)
11
- - [Token Injection System](#token-injection-system)
12
- - [Implementation Details](#implementation-details)
13
- - [Security Considerations](#security-considerations)
14
- - [Multi-Provider Support](#multi-provider-support)
15
- - [Examples](#examples)
16
- - [Troubleshooting](#troubleshooting)
17
-
18
- ## Overview
19
-
20
- ### Design Principles
21
-
22
- Matimo's OAuth2 implementation follows these core principles:
23
-
24
- 1. **Stateless Design**: Matimo does NOT store tokens. Users provide tokens via environment variables.
25
- 2. **YAML-Driven Configuration**: Provider OAuth endpoints and settings are defined in YAML, not hardcoded.
26
- 3. **Generic Parameter Injection**: Works for ANY provider (Gmail, GitHub, Slack) without hardcoding provider-specific logic.
27
- 4. **Framework-Agnostic**: OAuth flows happen outside Matimo; Matimo handles token injection and usage.
28
- 5. **Scalable**: Supports unlimited providers by adding YAML files only.
29
-
30
- ### Why This Approach?
31
-
32
- Traditional OAuth implementations are monolithic and provider-specific. Matimo separates concerns:
33
-
34
- - **OAuth Flows** (user authentication, token refresh) → Handled outside Matimo
35
- - **Token Storage** → User's responsibility (environment variables, secure vaults)
36
- - **Token Usage** → Matimo's responsibility (auto-inject into tool execution)
37
-
38
- This keeps Matimo lightweight and lets users manage OAuth however they prefer.
39
-
40
- ## Architecture
41
-
42
- ### System Layers
43
-
44
- ```
45
- ┌────────────────────────────────────────────────────────────────┐
46
- │ User Code / Framework (LangChain, CrewAI, custom) │
47
- │ └─ Sets: GMAIL_ACCESS_TOKEN=token123 │
48
- │ └─ Calls: matimo.execute('gmail-send-email', {to, subject}) │
49
- └───────────┬────────────────────────────────────────────────────┘
50
-
51
- ┌────────────────────────────────────────────────────────────────┐
52
- │ MatimoInstance (src/matimo-instance.ts) │
53
- │ ├─ execute(toolName, params) │
54
- │ ├─ 1. Load tool from YAML │
55
- │ ├─ 2. injectAuthParameters(tool, params) ← KEY STEP │
56
- │ │ └─ Pattern matching: looks for TOKEN/KEY/SECRET parameters │
57
- │ │ └─ Environment lookup: PARAM_NAME │
58
- │ │ └─ Merges found tokens into execution params │
59
- │ ├─ 3. Call executor (HttpExecutor, CommandExecutor) │
60
- │ └─ 4. Return result │
61
- └───────────┬────────────────────────────────────────────────────┘
62
-
63
- ┌────────────────────────────────────────────────────────────────┐
64
- │ Tool YAML Definition (tools/provider/tool-name.yaml) │
65
- │ ├─ execution: │
66
- │ │ ├─ type: http │
67
- │ │ ├─ url: https://gmail.googleapis.com/gmail/v1/users/me/... │
68
- │ │ ├─ headers: │
69
- │ │ │ └─ Authorization: "Bearer {GMAIL_ACCESS_TOKEN}" │
70
- │ │ ├─ query_params: {...} │
71
- │ │ └─ parameter_encoding: {...} │
72
- │ ├─ authentication: │
73
- │ │ ├─ type: oauth2 │
74
- │ │ ├─ provider: gmail │
75
- │ │ └─ required_scopes: [...] │
76
- │ └─ parameters: {...} │
77
- └───────────┬────────────────────────────────────────────────────┘
78
-
79
- ┌────────────────────────────────────────────────────────────────┐
80
- │ Provider Config YAML (tools/provider/definition.yaml) │
81
- │ ├─ Centralized OAuth2 endpoints │
82
- │ ├─ Example for Gmail: │
83
- │ │ ├─ token_url: https://oauth2.googleapis.com/token │
84
- │ │ ├─ auth_url: https://accounts.google.com/o/oauth2/auth │
85
- │ │ ├─ scopes: {gmail: [...], drive: [...]} │
86
- │ │ └─ redirect_uri: https://localhost:3000/callback │
87
- │ └─ Used by OAuth2ProviderLoader │
88
- └────────────────────────────────────────────────────────────────┘
89
- ```
90
-
91
- ### Core Components
92
-
93
- | Component | Purpose | Location |
94
- |-----------|---------|----------|
95
- | **MatimoInstance** | Main SDK class; orchestrates execution | `src/matimo-instance.ts` |
96
- | **injectAuthParameters()** | Pattern-based token injection | `src/matimo-instance.ts` |
97
- | **OAuth2ProviderLoader** | Loads provider config from YAML | `src/auth/oauth2-provider-loader.ts` |
98
- | **OAuth2ProviderConfig** | In-memory provider configuration | `src/auth/oauth2-provider-config.ts` |
99
- | **ToolDefinition** | Type for tool schemas | `src/core/types.ts` |
100
- | **HttpExecutor** | Executes HTTP requests | `src/executors/http-executor.ts` |
101
-
102
- ## OAuth2 Flow
103
-
104
- ### Standard OAuth2 Authorization Flow
105
-
106
- Matimo supports the **Authorization Code Flow** (most common for web apps and CLI tools):
107
-
108
- ```
109
- User Application Google OAuth Server
110
- ↓ ↑
111
- 1. Redirect to Google │
112
- GET https://accounts.google.com/o/oauth2/auth
113
- ?client_id=YOUR_CLIENT_ID
114
- &redirect_uri=http://localhost:3000/callback
115
- &scope=https://www.googleapis.com/auth/gmail.send
116
- &response_type=code
117
- └───────────────────────────────────────────→
118
-
119
- 2. User clicks "Allow"
120
-
121
- 3. Browser redirected to callback ←──────┘
122
- with authorization code (auth_code)
123
-
124
- 4. Exchange code for token (backend)
125
- POST https://oauth2.googleapis.com/token
126
- {
127
- code: auth_code,
128
- client_id: YOUR_CLIENT_ID,
129
- client_secret: YOUR_CLIENT_SECRET,
130
- grant_type: "authorization_code"
131
- }
132
- └───────────────────────────────────────────→
133
-
134
- 5. Receive access_token + refresh_token ←───┘
135
-
136
- 6. Store access_token (env var, secure vault)
137
-
138
- 7. Use with Matimo:
139
- process.env.GMAIL_ACCESS_TOKEN = access_token
140
- await matimo.execute('gmail-send-email', {...})
141
- ```
142
-
143
- ### Matimo's Role in the Flow
144
-
145
- **What Matimo DOES:**
146
- - ✅ Inject tokens into tool execution (step 7)
147
- - ✅ Validate token is present before execution
148
- - ✅ Handle token in HTTP headers correctly
149
- - ✅ Support token override at runtime
150
-
151
- **What Matimo DOES NOT Do:**
152
- - ❌ Perform OAuth authorization (steps 1-2)
153
- - ❌ Exchange code for token (step 4)
154
- - ❌ Store tokens (step 6)
155
- - ❌ Refresh expired tokens
156
- - ❌ Handle user login/logout
157
-
158
- **Why?** Matimo is framework-agnostic and stateless. OAuth flows vary by framework and security requirements.
159
-
160
- ### Token Lifecycle in Matimo
161
-
162
- ```
163
- ┌─────────────────────────────────────────────────────────────┐
164
- │ 1. User obtains token (outside Matimo) │
165
- │ - Via OAuth playground │
166
- │ - Via OAuth library (google-auth-library, etc.) │
167
- │ - Via custom OAuth flow │
168
- └────────────┬────────────────────────────────────────────────┘
169
-
170
- ┌─────────────────────────────────────────────────────────────┐
171
- │ 2. Store token in environment │
172
- │ export GMAIL_ACCESS_TOKEN=ya29.a0AXooCg... │
173
- └────────────┬────────────────────────────────────────────────┘
174
-
175
- ┌─────────────────────────────────────────────────────────────┐
176
- │ 3. Matimo injectAuthParameters() │
177
- │ - Scans tool's execution config for {PARAM} placeholders │
178
- │ - Finds {GMAIL_ACCESS_TOKEN} │
179
- │ - Looks up env: GMAIL_ACCESS_TOKEN │
180
- │ - Injects into request headers/body │
181
- └────────────┬────────────────────────────────────────────────┘
182
-
183
- ┌─────────────────────────────────────────────────────────────┐
184
- │ 4. HttpExecutor sends request with token │
185
- │ Authorization: Bearer ya29.a0AXooCg... │
186
- └────────────┬────────────────────────────────────────────────┘
187
-
188
- ┌─────────────────────────────────────────────────────────────┐
189
- │ 5. API validates token, executes request │
190
- └─────────────────────────────────────────────────────────────┘
191
- ```
192
-
193
- ## Provider YAML Configuration
194
-
195
- ### Provider Definition File Structure
196
-
197
- Each provider has a central configuration file: `tools/{provider}/definition.yaml`
198
-
199
- **Example: Gmail Provider** (`tools/gmail/definition.yaml`)
200
-
201
- ```yaml
202
- provider:
203
- name: gmail
204
- description: Google Gmail API
205
- documentation_url: https://developers.google.com/gmail/api
206
-
207
- oauth2:
208
- # OAuth2 endpoints
209
- auth_url: https://accounts.google.com/o/oauth2/auth
210
- token_url: https://oauth2.googleapis.com/token
211
- revoke_url: https://oauth2.googleapis.com/revoke
212
-
213
- # Scopes for different permission levels
214
- scopes:
215
- send:
216
- - https://www.googleapis.com/auth/gmail.send
217
- - https://www.googleapis.com/auth/gmail.readonly
218
- draft:
219
- - https://www.googleapis.com/auth/gmail.modify
220
- full_access:
221
- - https://www.googleapis.com/auth/gmail
222
-
223
- # Default redirect URI for local dev
224
- redirect_uri: http://localhost:3000/callback
225
-
226
- # If your app needs specific settings
227
- approval_prompt: force # Force consent screen
228
- access_type: offline # Get refresh token
229
-
230
- # Override mechanism (defined in tool YAML)
231
- parameter_mapping:
232
- # Maps parameter names to environment variable patterns
233
- - parameter: GMAIL_ACCESS_TOKEN
234
- env_pattern: "GMAIL_ACCESS_TOKEN"
235
- required: true
236
- description: "Gmail OAuth access token"
237
- ```
238
-
239
- ### Supported Provider Fields
240
-
241
- | Field | Type | Required | Description |
242
- |-------|------|----------|-------------|
243
- | `provider.name` | string | Yes | Provider identifier (gmail, github, slack) |
244
- | `provider.description` | string | No | Human-readable description |
245
- | `oauth2.auth_url` | string | Yes | Authorization endpoint |
246
- | `oauth2.token_url` | string | Yes | Token exchange endpoint |
247
- | `oauth2.revoke_url` | string | No | Token revocation endpoint |
248
- | `oauth2.scopes` | object | Yes | Available OAuth scopes (grouped by feature) |
249
- | `oauth2.redirect_uri` | string | Yes | Redirect URI after user authorizes |
250
- | `oauth2.approval_prompt` | string | No | "force" to always show consent screen |
251
- | `oauth2.access_type` | string | No | "offline" to get refresh token |
252
-
253
- ## Token Injection System
254
-
255
- ### How Matimo Auto-Injects Tokens
256
-
257
- The `injectAuthParameters()` method in `MatimoInstance` performs three steps:
258
-
259
- #### Step 1: Extract Parameter Placeholders
260
-
261
- Scan the tool's execution config for `{PARAM_NAME}` patterns:
262
-
263
- ```yaml
264
- execution:
265
- type: http
266
- url: "https://gmail.googleapis.com/..."
267
- headers:
268
- Authorization: "Bearer {GMAIL_ACCESS_TOKEN}" # ← Found!
269
- body:
270
- message: "{COMPOSED_MESSAGE}" # ← Found!
271
- ```
272
-
273
- Result: Array of found parameters: `["GMAIL_ACCESS_TOKEN", "COMPOSED_MESSAGE"]`
274
-
275
- #### Step 2: Identify Auth Parameters
276
-
277
- Filter by pattern matching (parameters are auth-related if they contain):
278
- - `TOKEN`
279
- - `KEY`
280
- - `SECRET`
281
- - `PASSWORD`
282
- - `CREDENTIAL`
283
- - `APIKEY`
284
-
285
- Example:
286
- - ✅ `GMAIL_ACCESS_TOKEN` → Contains "TOKEN" → Auth parameter
287
- - ✅ `API_KEY` → Contains "KEY" → Auth parameter
288
- - ❌ `COMPOSED_MESSAGE` → No match → User parameter (not injected)
289
-
290
- #### Step 3: Environment Lookup & Injection
291
-
292
- For each auth parameter, look up environment variables:
293
-
294
- ```typescript
295
- // Parameter: GMAIL_ACCESS_TOKEN
296
-
297
- // Try 1: prefix (recommended)
298
- process.env.GMAIL_ACCESS_TOKEN
299
- // Falls back to:
300
-
301
- // Try 2: Direct name
302
- process.env.GMAIL_ACCESS_TOKEN
303
- ```
304
-
305
- If found, inject into execution parameters.
306
-
307
- ### Code Implementation
308
-
309
- ```typescript
310
- // In src/matimo-instance.ts
311
-
312
- private injectAuthParameters(
313
- tool: ToolDefinition,
314
- params: Record<string, any>
315
- ): Record<string, any> {
316
- // Step 1: Extract parameter placeholders from execution config
317
- const placeholders = this.extractParameterPlaceholders(
318
- tool.execution
319
- );
320
-
321
- // Step 2 & 3: For each placeholder, attempt to inject from environment
322
- const injected = { ...params };
323
-
324
- for (const placeholder of placeholders) {
325
- // Check if this looks like an auth parameter
326
- if (this.isAuthParameter(placeholder)) {
327
- // Try prefix first, then fallback to direct name
328
- const envKey = `${placeholder}`;
329
- let value = process.env[envKey] || process.env[placeholder];
330
-
331
- if (value) {
332
- injected[placeholder] = value;
333
- }
334
- }
335
- }
336
-
337
- return injected;
338
- }
339
-
340
- private extractParameterPlaceholders(
341
- obj: any
342
- ): string[] {
343
- const placeholders: string[] = [];
344
- const regex = /\{(\w+)\}/g;
345
-
346
- const scan = (value: any) => {
347
- if (typeof value === 'string') {
348
- let match;
349
- while ((match = regex.exec(value)) !== null) {
350
- placeholders.push(match[1]);
351
- }
352
- } else if (typeof value === 'object' && value !== null) {
353
- Object.values(value).forEach(scan);
354
- }
355
- };
356
-
357
- scan(obj);
358
- return [...new Set(placeholders)]; // Deduplicate
359
- }
360
-
361
- private isAuthParameter(name: string): boolean {
362
- const authPatterns = [
363
- 'TOKEN', 'KEY', 'SECRET', 'PASSWORD',
364
- 'CREDENTIAL', 'APIKEY', 'AUTH'
365
- ];
366
- return authPatterns.some(pattern =>
367
- name.toUpperCase().includes(pattern)
368
- );
369
- }
370
- ```
371
-
372
- ### Token Injection Examples
373
-
374
- #### Example 1: Gmail Send Email
375
-
376
- **Tool YAML:**
377
- ```yaml
378
- name: send-email
379
- execution:
380
- type: http
381
- method: post
382
- url: https://gmail.googleapis.com/gmail/v1/users/me/messages/send
383
- headers:
384
- Authorization: "Bearer {GMAIL_ACCESS_TOKEN}"
385
- body:
386
- raw: "{ENCODED_MESSAGE}"
387
- ```
388
-
389
- **User Code:**
390
- ```typescript
391
- process.env.GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg...";
392
-
393
- await matimo.execute('gmail-send-email', {
394
- to: 'user@example.com',
395
- subject: 'Hello',
396
- body: 'Test message',
397
- // GMAIL_ACCESS_TOKEN NOT needed - auto-injected!
398
- });
399
- ```
400
-
401
- **What Happens:**
402
- 1. User provides: `to`, `subject`, `body`
403
- 2. Matimo extracts placeholders: `GMAIL_ACCESS_TOKEN`, `ENCODED_MESSAGE`
404
- 3. Matimo identifies `GMAIL_ACCESS_TOKEN` as auth parameter (contains "TOKEN")
405
- 4. Matimo looks up `GMAIL_ACCESS_TOKEN` → found
406
- 5. Matimo injects: `GMAIL_ACCESS_TOKEN: "ya29.a0AXooCg..."`
407
- 6. Request sent with `Authorization: Bearer ya29.a0AXooCg...`
408
-
409
- #### Example 2: GitHub Repository API
410
-
411
- **Tool YAML:**
412
- ```yaml
413
- name: get-repo-info
414
- execution:
415
- type: http
416
- url: https://api.github.com/repos/{owner}/{repo}
417
- headers:
418
- Authorization: "Bearer {GITHUB_API_KEY}"
419
- Accept: "application/vnd.github.v3+json"
420
- ```
421
-
422
- **User Code:**
423
- ```typescript
424
- process.env.GITHUB_API_KEY = "ghp_abc123...";
425
-
426
- await matimo.execute('get-repo-info', {
427
- owner: 'torvalds',
428
- repo: 'linux',
429
- // GITHUB_API_KEY auto-injected
430
- });
431
- ```
432
-
433
- ## Implementation Details
434
-
435
- ### Files & Locations
436
-
437
- | File | Purpose |
438
- |------|---------|
439
- | `src/matimo-instance.ts` | Main SDK class, contains `injectAuthParameters()` |
440
- | `src/auth/oauth2-provider-config.ts` | OAuth2 provider configuration loader |
441
- | `src/auth/oauth2-provider-loader.ts` | YAML provider file parser |
442
- | `src/core/types.ts` | `ToolDefinition` interface |
443
- | `src/executors/http-executor.ts` | HTTP request execution |
444
- | `tools/{provider}/definition.yaml` | Provider OAuth configuration |
445
- | `tools/{provider}/{tool}.yaml` | Individual tool definitions |
446
-
447
- ### OAuth2ProviderLoader
448
-
449
- ```typescript
450
- // Load provider config from YAML
451
- const loader = new OAuth2ProviderLoader('./tools');
452
- const gmailConfig = await loader.loadProvider('gmail');
453
-
454
- // Result:
455
- {
456
- name: 'gmail',
457
- oauth2: {
458
- auth_url: '...',
459
- token_url: '...',
460
- scopes: { ... }
461
- }
462
- }
463
- ```
464
-
465
- ### OAuth2ProviderConfig
466
-
467
- ```typescript
468
- // In-memory provider config storage
469
- const config = new OAuth2ProviderConfig();
470
-
471
- // Register provider
472
- await config.addProvider('gmail', gmailConfig);
473
-
474
- // Retrieve provider
475
- const provider = config.getProvider('gmail');
476
-
477
- // List all providers
478
- const all = config.getAllProviders();
479
- ```
480
-
481
- ## Security Considerations
482
-
483
- ### ✅ Security Best Practices
484
-
485
- #### 1. Token Storage
486
-
487
- **DON'T:**
488
- ```bash
489
- # ❌ Bad: Token in code
490
- const token = "ya29.a0AXooCg...";
491
- ```
492
-
493
- **DO:**
494
- ```bash
495
- # ✅ Good: Token in environment variable
496
- export GMAIL_ACCESS_TOKEN="ya29.a0AXooCg..."
497
-
498
- # ✅ Better: Use .env file with .gitignore
499
- # .env (never commit)
500
- GMAIL_ACCESS_TOKEN=ya29.a0AXooCg...
501
-
502
- # .gitignore
503
- .env
504
- .env.local
505
- ```
506
-
507
- **✅ BEST: Secure Vault**
508
- ```bash
509
- # Use 1Password, LastPass, AWS Secrets Manager, etc.
510
- # Retrieve at runtime:
511
- const token = await vault.getSecret('matimo-gmail-token');
512
- process.env.GMAIL_ACCESS_TOKEN = token;
513
- ```
514
-
515
- #### 2. Token Permissions (Scopes)
516
-
517
- Always request minimum required scopes:
518
-
519
- ```yaml
520
- # ❌ Bad: Full access
521
- scopes:
522
- - https://www.googleapis.com/auth/gmail
523
-
524
- # ✅ Good: Specific scopes
525
- scopes:
526
- send:
527
- - https://www.googleapis.com/auth/gmail.send # Send only
528
- read:
529
- - https://www.googleapis.com/auth/gmail.readonly # Read only
530
- ```
531
-
532
- #### 3. Token Expiration
533
-
534
- Monitor token expiration and refresh:
535
-
536
- ```typescript
537
- // Token expiration typically: 1 hour for access tokens
538
- // What to do when expired:
539
-
540
- // Option 1: Refresh token (Phase 2 feature)
541
- const newToken = await oauth2.refreshToken(refreshToken);
542
- process.env.GMAIL_ACCESS_TOKEN = newToken;
543
-
544
- // Option 2: Re-authorize
545
- console.error('Token expired. Please re-authenticate:');
546
- console.log('Visit: https://oauth2.example.com/authorize');
547
- ```
548
-
549
- #### 4. Token Revocation
550
-
551
- Always revoke tokens when done:
552
-
553
- ```typescript
554
- // After tool execution completes
555
- await oauth2.revokeToken(accessToken, {
556
- provider: 'gmail',
557
- revoke_url: 'https://oauth2.googleapis.com/revoke'
558
- });
559
- ```
560
-
561
- #### 5. Log Sanitization
562
-
563
- Never log tokens:
564
-
565
- ```typescript
566
- // ❌ Bad: Token in logs
567
- logger.info('Sending email', {
568
- token: params.GMAIL_ACCESS_TOKEN, // DANGER!
569
- to: 'user@example.com'
570
- });
571
-
572
- // ✅ Good: Sanitize sensitive data
573
- const sanitized = {
574
- to: params.to,
575
- subject: params.subject,
576
- // token: never logged
577
- };
578
- logger.info('Sending email', sanitized);
579
- ```
580
-
581
- ### 🛡️ Attack Mitigation
582
-
583
- #### Cross-Site Request Forgery (CSRF) Protection
584
-
585
- When implementing OAuth flow (Phase 2):
586
-
587
- ```typescript
588
- // Generate random state parameter
589
- const state = crypto.randomBytes(32).toString('hex');
590
- session.setState(state);
591
-
592
- // Verify state in callback
593
- if (request.query.state !== session.getState()) {
594
- throw new Error('State mismatch - CSRF attack?');
595
- }
596
- ```
597
-
598
- #### Token Leakage Prevention
599
-
600
- ```typescript
601
- // ❌ Never expose tokens in URLs
602
- GET /api/tool?token=ya29.a0AXooCg...
603
-
604
- // ✅ Always use headers or POST body
605
- headers: {
606
- Authorization: 'Bearer ya29.a0AXooCg...'
607
- }
608
- ```
609
-
610
- #### Secret Rotation
611
-
612
- ```yaml
613
- # tools/gmail/definition.yaml
614
- oauth2:
615
- client_id: ${GMAIL_CLIENT_ID} # From env
616
- client_secret: ${GMAIL_CLIENT_SECRET} # From env (rotate regularly)
617
- # Schedule periodic secret rotation in your OAuth app settings
618
- ```
619
-
620
- ## Multi-Provider Support
621
-
622
- ### Adding a New Provider
623
-
624
- Matimo supports unlimited providers without code changes.
625
-
626
- #### Step 1: Create Provider Config
627
-
628
- Create `tools/{provider}/definition.yaml`:
629
-
630
- ```yaml
631
- # tools/github/definition.yaml
632
- provider:
633
- name: github
634
- description: GitHub API
635
- documentation_url: https://docs.github.com/en/rest
636
-
637
- oauth2:
638
- auth_url: https://github.com/login/oauth/authorize
639
- token_url: https://github.com/login/oauth/access_token
640
- revoke_url: https://api.github.com/applications/{client_id}/token
641
-
642
- scopes:
643
- read:
644
- - repo:status
645
- - public_repo
646
- write:
647
- - repo
648
- admin:
649
- - admin:repo_hook
650
- - admin:user
651
-
652
- redirect_uri: http://localhost:3000/callback
653
- access_type: offline # Get refresh token
654
- ```
655
-
656
- #### Step 2: Create Tool Definitions
657
-
658
- Create `tools/github/{tool}.yaml` files:
659
-
660
- ```yaml
661
- # tools/github/get-repo.yaml
662
- name: get-repo
663
- description: Get GitHub repository information
664
- version: '1.0.0'
665
-
666
- parameters:
667
- owner:
668
- type: string
669
- required: true
670
- description: Repository owner
671
- repo:
672
- type: string
673
- required: true
674
- description: Repository name
675
-
676
- execution:
677
- type: http
678
- method: get
679
- url: "https://api.github.com/repos/{owner}/{repo}"
680
- headers:
681
- Authorization: "Bearer {GITHUB_API_KEY}"
682
- Accept: "application/vnd.github.v3+json"
683
-
684
- authentication:
685
- type: oauth2
686
- provider: github
687
- required_scopes:
688
- - public_repo
689
-
690
- output_schema:
691
- type: object
692
- properties:
693
- name:
694
- type: string
695
- full_name:
696
- type: string
697
- stars:
698
- type: integer
699
- description:
700
- type: string
701
- ```
702
-
703
- #### Step 3: Use in Code
704
-
705
- No code changes needed!
706
-
707
- ```typescript
708
- // Matimo automatically discovers and loads tools/github/*.yaml
709
- const tools = await loader.loadToolsFromDirectory('./tools');
710
-
711
- // GitHub tools are now available
712
- await matimo.execute('get-repo', {
713
- owner: 'torvalds',
714
- repo: 'linux'
715
- // GITHUB_API_KEY auto-injected from GITHUB_API_KEY
716
- });
717
- ```
718
-
719
- ### Runtime Override Example
720
-
721
- ```typescript
722
- // Override provider endpoint at runtime
723
- const tool = tools.find(t => t.name === 'get-repo');
724
-
725
- // Option 1: Env variable
726
- process.env.GITHUB_API_KEY = 'custom-token';
727
-
728
- // Option 2: Runtime argument
729
- const result = await matimo.execute('get-repo', {
730
- owner: 'torvalds',
731
- repo: 'linux',
732
- GITHUB_API_KEY: 'custom-token' // Overrides env
733
- });
734
- ```
735
-
736
- ## Token Passing Methods
737
-
738
- ### How Users Can Pass Tokens
739
-
740
- Users have **multiple flexible options** to pass tokens to Matimo - not just environment variables:
741
-
742
- #### Option 1: Explicit Parameter (Highest Priority)
743
-
744
- Pass the token directly in the execute call. This is the most flexible and secure approach:
745
-
746
- ```typescript
747
- const token = await getTokenFromVault('gmail'); // Get from vault, database, etc.
748
-
749
- await matimo.execute('send-email', {
750
- to: 'user@example.com',
751
- subject: 'Hello',
752
- body: 'Test',
753
- GMAIL_ACCESS_TOKEN: token // ✅ Explicit - takes precedence!
754
- });
755
- ```
756
-
757
- **Advantages:**
758
- - ✅ Most secure (tokens not stored in env)
759
- - ✅ Per-request flexibility
760
- - ✅ Multi-tenant support
761
- - ✅ Works with secure vaults
762
-
763
- **Use cases:** Production, microservices, multi-tenant apps
764
-
765
- #### Option 2: Runtime Environment Variable
766
-
767
- Set the environment variable at runtime from a vault or database:
768
-
769
- ```typescript
770
- // Fetch token at startup
771
- const token = await secretsManager.getSecret('matimo-gmail-token');
772
-
773
- // Set in environment
774
- process.env.GMAIL_ACCESS_TOKEN = token;
775
-
776
- // Token auto-injected in all execute calls
777
- await matimo.execute('send-email', {
778
- to: 'user@example.com',
779
- subject: 'Hello',
780
- body: 'Test'
781
- // Token auto-injected from process.env
782
- });
783
- ```
784
-
785
- **Advantages:**
786
- - ✅ Clean code (auto-injection)
787
- - ✅ Simple to implement
788
- - ✅ Works across app
789
-
790
- **Use cases:** Development, single-tenant apps, startups
791
-
792
- #### Option 3: Combination (Best Practice)
793
-
794
- Use both approaches together:
795
-
796
- ```typescript
797
- // At app startup - set env var
798
- process.env.GMAIL_ACCESS_TOKEN = initialToken;
799
-
800
- // Later - override for specific request if needed
801
- await matimo.execute('send-email', {
802
- to: 'user@example.com',
803
- subject: 'Hello',
804
- body: 'Test',
805
- GMAIL_ACCESS_TOKEN: differentToken // Override for this request
806
- });
807
-
808
- // Other requests - use env var (auto-injected)
809
- await matimo.execute('send-email', {
810
- to: 'other@example.com',
811
- subject: 'Hello',
812
- body: 'Test'
813
- // Uses GMAIL_ACCESS_TOKEN from env
814
- });
815
- ```
816
-
817
- ### Token Resolution Priority
818
-
819
- When Matimo needs a token, it checks in this order:
820
-
821
- ```
822
- 1. Explicit parameter (highest priority)
823
- └─ await matimo.execute('tool', { GMAIL_ACCESS_TOKEN: 'explicit' })
824
-
825
- 2. Environment variable (fallback)
826
- ├─ process.env.GMAIL_ACCESS_TOKEN
827
- └─ process.env.GMAIL_ACCESS_TOKEN (if not found)
828
-
829
- 3. Not found (lowest priority)
830
- └─ Error: "Missing required parameter: GMAIL_ACCESS_TOKEN"
831
- ```
832
-
833
- The first match wins - others are ignored.
834
-
835
- ### Real-World Examples
836
-
837
- #### Example: Secure Vault (AWS Secrets Manager)
838
-
839
- ```typescript
840
- import AWS from 'aws-sdk';
841
-
842
- const secretsManager = new AWS.SecretsManager();
843
-
844
- async function executeWithVaultToken(toolName, params) {
845
- // Fetch token from AWS Secrets Manager at runtime
846
- const secret = await secretsManager.getSecretValue({
847
- SecretId: 'matimo-gmail-token'
848
- });
849
-
850
- const token = JSON.parse(secret.SecretString).token;
851
-
852
- // Pass explicitly - never stored in code or env
853
- return await matimo.execute(toolName, {
854
- ...params,
855
- GMAIL_ACCESS_TOKEN: token
856
- });
857
- }
858
-
859
- // Usage
860
- await executeWithVaultToken('send-email', {
861
- to: 'user@example.com',
862
- subject: 'Hello',
863
- body: 'Test'
864
- });
865
- ```
866
-
867
- #### Example: Multi-Tenant Application
868
-
869
- ```typescript
870
- // Different token per user/tenant
871
- async function sendEmailForUser(userId, mailParams) {
872
- const user = await db.users.findById(userId);
873
- const userToken = user.gmail_access_token; // From database
874
-
875
- return await matimo.execute('send-email', {
876
- ...mailParams,
877
- GMAIL_ACCESS_TOKEN: userToken // User-specific token
878
- });
879
- }
880
-
881
- // Each user has their own token
882
- await sendEmailForUser('user-1', {to, subject, body});
883
- await sendEmailForUser('user-2', {to, subject, body});
884
- ```
885
-
886
- #### Example: Token Refresh Handler
887
-
888
- ```typescript
889
- class TokenManager {
890
- private currentToken: string;
891
-
892
- async ensureValidToken() {
893
- // Check if token expired
894
- if (this.isTokenExpired(this.currentToken)) {
895
- // Refresh and update
896
- this.currentToken = await this.refreshAccessToken();
897
- process.env.GMAIL_ACCESS_TOKEN = this.currentToken;
898
- }
899
- return this.currentToken;
900
- }
901
-
902
- async execute(toolName, params) {
903
- const token = await this.ensureValidToken();
904
-
905
- return await matimo.execute(toolName, {
906
- ...params,
907
- GMAIL_ACCESS_TOKEN: token // Always fresh
908
- });
909
- }
910
- }
911
-
912
- // Usage
913
- const tokenManager = new TokenManager();
914
- await tokenManager.execute('send-email', {to, subject, body});
915
- ```
916
-
917
- #### Example: OAuth Callback Handler (Phase 2 Preparation)
918
-
919
- ```typescript
920
- async function handleOAuthCallback(code, userId) {
921
- // Exchange code for token
922
- const tokens = await oauth2.exchangeCode(code);
923
-
924
- // Store tokens (choose one approach)
925
-
926
- // Option A: Database
927
- await db.users.update(userId, {
928
- gmail_access_token: tokens.access_token,
929
- gmail_refresh_token: tokens.refresh_token,
930
- token_expires_at: Date.now() + tokens.expires_in * 1000
931
- });
932
-
933
- // Option B: Secure Vault (AWS Secrets Manager, 1Password, etc.)
934
- await vault.setSecret(
935
- `user-${userId}-gmail-token`,
936
- tokens.access_token
937
- );
938
-
939
- // Later, when executing tools:
940
- const token = await db.users.findById(userId).gmail_access_token;
941
- // OR
942
- const token = await vault.getSecret(`user-${userId}-gmail-token`);
943
-
944
- // Pass to Matimo
945
- await matimo.execute('send-email', {
946
- to: 'user@example.com',
947
- subject: 'Hello',
948
- body: 'Test',
949
- GMAIL_ACCESS_TOKEN: token // Explicit token
950
- });
951
- }
952
- ```
953
-
954
- ### Comparison: Which Approach to Use?
955
-
956
- | Approach | Pros | Cons | Best For |
957
- |----------|------|------|----------|
958
- | **Explicit Parameter** | 🔒 Secure, flexible, per-request, no env vars | More verbose | Production, multi-tenant, microservices |
959
- | **Runtime Environment** | ✨ Clean code, auto-injection, simple | Token in memory, app-wide | Development, single-tenant, startups |
960
- | **Vault/Secrets Manager** | 🛡️ Enterprise-secure, auditable, centralized | Extra infrastructure, complexity | Enterprise apps, compliance-required |
961
- | **OAuth Flow** | 🔑 User-authenticated, standards-based | Phase 2 (not yet) | Future production apps |
962
-
963
- ## Examples
964
-
965
- ### Example 1: Gmail with Factory Pattern
966
-
967
- ```typescript
968
- // examples/langchain/gmail/gmail-factory.ts
969
-
970
- import { MatimoInstance, ToolLoader } from '../../../src';
971
-
972
- // Set up Matimo
973
- const loader = new ToolLoader('./tools');
974
- const tools = await loader.loadToolsFromDirectory();
975
- const matimo = new MatimoInstance(tools);
976
-
977
- // Gmail access token from environment
978
- process.env.GMAIL_ACCESS_TOKEN = 'ya29.a0AXooCg...';
979
-
980
- // Execute without passing token explicitly
981
- const result = await matimo.execute('send-email', {
982
- to: 'recipient@example.com',
983
- subject: 'Hello from Matimo',
984
- body: 'This is a test message'
985
- // Token auto-injected!
986
- });
987
-
988
- console.log('Email sent:', result.id);
989
- ```
990
-
991
- ### Example 2: GitHub with Decorator Pattern
992
-
993
- ```typescript
994
- // Example: Decorator auto-injects GITHUB_API_KEY
995
-
996
- import { tool } from '../../../src';
997
-
998
- @tool('get-repo')
999
- async getGithubRepo(owner: string, repo: string) {
1000
- return undefined; // Matimo intercepts
1001
- }
1002
-
1003
- // Set token
1004
- process.env.GITHUB_API_KEY = 'ghp_abc123...';
1005
-
1006
- // Call - no token needed
1007
- const repo = await getGithubRepo('torvalds', 'linux');
1008
- console.log(repo.name); // 'linux'
1009
- ```
1010
-
1011
- ### Example 3: AI Agent Deciding Which Tool to Use
1012
-
1013
- ```typescript
1014
- // examples/langchain/gmail/gmail-langchain.ts
1015
-
1016
- import { MatimoInstance, ToolLoader } from '../../../src';
1017
- import { ChatOpenAI } from '@langchain/openai';
1018
- import { createToolsForAgent } from '@langchain/core/tools';
1019
-
1020
- const loader = new ToolLoader('./tools');
1021
- const tools = await loader.loadToolsFromDirectory();
1022
- const matimo = new MatimoInstance(tools);
1023
-
1024
- // Set access tokens
1025
- process.env.GMAIL_ACCESS_TOKEN = 'ya29.a0AXooCg...';
1026
-
1027
- // Create LangChain tools from YAML
1028
- const langchainTools = createToolsForAgent(
1029
- tools.filter(t => t.name.startsWith('gmail-'))
1030
- );
1031
-
1032
- // Agent decides which tool to use based on user request
1033
- const agent = new OpenAIAgent({
1034
- llm: new ChatOpenAI({ model: 'gpt-4' }),
1035
- tools: langchainTools
1036
- });
1037
-
1038
- // User says what they want in natural language
1039
- const result = await agent.invoke({
1040
- messages: [{
1041
- role: 'user',
1042
- content: 'Send an email to alice@example.com saying hello'
1043
- }]
1044
- });
1045
-
1046
- // Agent chooses 'send-email' tool, passes parameters,
1047
- // Matimo injects GMAIL_ACCESS_TOKEN, email is sent!
1048
- ```
1049
-
1050
- ## Architecture Diagrams
1051
-
1052
- ### Token Injection System Flow
1053
-
1054
- ```
1055
- ┌──────────────────────────────────────────────────────────────────┐
1056
- │ User Code │
1057
- │ process.env.GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg..." │
1058
- │ await matimo.execute('send-email', {to, subject, body}) │
1059
- └───────────┬──────────────────────────────────────────────────────┘
1060
-
1061
-
1062
- ┌──────────────────────────────────────────────────────────────────┐
1063
- │ MatimoInstance.execute() │
1064
- │ 1. Load tool from registry │
1065
- │ name: 'send-email' │
1066
- │ execution: │
1067
- │ headers: │
1068
- │ Authorization: "Bearer {GMAIL_ACCESS_TOKEN}" │
1069
- └───────────┬──────────────────────────────────────────────────────┘
1070
-
1071
-
1072
- ┌──────────────────────────────────────────────────────────────────┐
1073
- │ injectAuthParameters(tool, params) │
1074
- │ Step 1: extractParameterPlaceholders(execution) │
1075
- │ Result: ["GMAIL_ACCESS_TOKEN", ...] │
1076
- └───────────┬──────────────────────────────────────────────────────┘
1077
-
1078
-
1079
- ┌──────────────────────────────────────────────────────────────────┐
1080
- │ isAuthParameter(placeholder) │
1081
- │ Check if contains: TOKEN, KEY, SECRET, PASSWORD, etc. │
1082
- │ "GMAIL_ACCESS_TOKEN" contains "TOKEN" ✓ │
1083
- └───────────┬──────────────────────────────────────────────────────┘
1084
-
1085
-
1086
- ┌──────────────────────────────────────────────────────────────────┐
1087
- │ Environment Variable Lookup │
1088
- │ Try: GMAIL_ACCESS_TOKEN ✓ Found! │
1089
- │ Value: "ya29.a0AXooCg..." │
1090
- └───────────┬──────────────────────────────────────────────────────┘
1091
-
1092
-
1093
- ┌───────────────────────────────────────────────────────────────────┐
1094
- │ Merge into Execution Parameters │
1095
- │ { │
1096
- │ GMAIL_ACCESS_TOKEN: "ya29.a0AXooCg...", │
1097
- │ to: "user@example.com", │
1098
- │ subject: "Hello", │
1099
- │ body: "Test" │
1100
- │ } │
1101
- └───────────┬───────────────────────────────────────────────────────┘
1102
-
1103
-
1104
- ┌──────────────────────────────────────────────────────────────────┐
1105
- │ HttpExecutor.execute() │
1106
- │ Replace {GMAIL_ACCESS_TOKEN} with actual token value │
1107
- │ Headers: { │
1108
- │ Authorization: "Bearer ya29.a0AXooCg..." │
1109
- │ } │
1110
- └───────────┬──────────────────────────────────────────────────────┘
1111
-
1112
-
1113
- ┌────────────────────────────────────────────────────────────────────┐
1114
- │ Send HTTP Request to Gmail API │
1115
- │ POST https://gmail.googleapis.com/gmail/v1/users/me/messages/send │
1116
- │ Headers: {Authorization: "Bearer ya29.a0AXooCg..."} │
1117
- └───────────┬────────────────────────────────────────────────────────┘
1118
-
1119
-
1120
- ┌───────────────────────────────────────────────────────────────────┐
1121
- │ Return Result to User │
1122
- │ { │
1123
- │ id: "thread123", │
1124
- │ threadId: "abc456", │
1125
- │ labelIds: ["SENT"] │
1126
- │ } │
1127
- └───────────────────────────────────────────────────────────────────┘
1128
- ```
1129
-
1130
- ### OAuth2 Standard Authorization Code Flow
1131
-
1132
- ```
1133
- ┌────────────────────┐ ┌──────────────────────┐
1134
- │ User's Browser │ │ Google Auth Server │
1135
- └────────┬───────────┘ └──────────┬───────────┘
1136
- │ │
1137
- │ 1. User clicks "Sign in with Google" │
1138
- ├──────────────────────────────────────────────────────────>
1139
- │ GET /oauth2/auth?client_id=...&scope=... │
1140
- │ │
1141
- │ 2. Google shows consent │
1142
- │ screen │
1143
- │ <─────────────────────────────────────────────────────
1144
- │ (User sees: "Allow app to send emails?") │
1145
- │ │
1146
- │ 3. User clicks "Allow" │
1147
- │ │
1148
- │ Redirect to callback with code │
1149
- │ <─────────────────────────────────────────────────────
1150
- │ Location: http://localhost:3000/callback?code=abc123
1151
-
1152
- ┌────────┴───────────┐
1153
- │ Your Backend │ 4. Exchange code for token
1154
- │ /callback handler │ POST https://oauth2.googleapis.com/token
1155
- └────────┬───────────┘ body: {code, client_id, client_secret}
1156
- │ │
1157
- │ │
1158
- │──────────────────────────────────────────────────────────>
1159
- │ Google
1160
- │ exchanges
1161
- │ code
1162
- │ │
1163
- │ 5. Receive tokens │
1164
- │ { │
1165
- │ access_token: "ya29.a0AXooCg...", │
1166
- │ refresh_token: "1//0gXKJV...", │
1167
- │ expires_in: 3600 │
1168
- │ } │
1169
- │ <─────────────────────────────────────────────────────
1170
-
1171
- └─ 6. Store tokens securely
1172
- (database, secure vault, env var)
1173
-
1174
- └─ 7. Use with Matimo
1175
- process.env.GMAIL_ACCESS_TOKEN = token
1176
- matimo.execute('send-email', {...})
1177
- ```
1178
-
1179
- ### Environment Variable Resolution
1180
-
1181
- ```
1182
- Parameter Name: GMAIL_ACCESS_TOKEN
1183
-
1184
- ┌──────────────────────────────────────────────────────────┐
1185
- │ Check 1: Prefixed (Recommended) │
1186
- │ │
1187
- │ process.env.GMAIL_ACCESS_TOKEN │
1188
- │ │
1189
- │ ✓ If found → Use it │
1190
- │ │ │
1191
- │ └─> GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg..." │
1192
- │ │
1193
- └──────────────────────────────────────────────────────────┘
1194
-
1195
- │ NOT FOUND
1196
-
1197
- ┌─────────────────────────────────────────────────────────┐
1198
- │ Check 2: Direct Name (Fallback) │
1199
- │ │
1200
- │ process.env.GMAIL_ACCESS_TOKEN │
1201
- │ │
1202
- │ ✓ If found → Use it │
1203
- │ │ │
1204
- │ └─> GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg..." │
1205
- │ │
1206
- └─────────────────────────────────────────────────────────┘
1207
-
1208
- │ NOT FOUND
1209
-
1210
- ┌─────────────────────────────────────────────────────────┐
1211
- │ No Token Found │
1212
- │ │
1213
- │ Parameter not injected │
1214
- │ Tool execution may fail if token was required │
1215
- │ │
1216
- │ Error: "Missing required parameter: GMAIL_ACCESS_TOKEN" │
1217
- │ │
1218
- └─────────────────────────────────────────────────────────┘
1219
- ```
1220
-
1221
- ## Quick Reference
1222
-
1223
- ### Getting Started (5 Steps)
1224
-
1225
- 1. **Obtain Token** - Via OAuth Playground or your app's auth flow
1226
- 2. **Set Environment** - `export GMAIL_ACCESS_TOKEN=token`
1227
- 3. **Load Tools** - `await loader.loadToolsFromDirectory()`
1228
- 4. **Execute** - `await matimo.execute('tool-name', params)`
1229
- 5. **Handle Errors** - Check error code and token validity
1230
-
1231
- ### Common Patterns
1232
-
1233
- | Pattern | Use Case | Token Passing |
1234
- |---------|----------|---------------|
1235
- | **Factory** | Scripts, direct SDK | Auto-inject from env |
1236
- | **Decorator** | Framework integration | Auto-inject from env |
1237
- | **AI Agent** | LLM-driven tools | Auto-inject from env |
1238
- | **Environment File** | Local development | Load from `.env` |
1239
- | **Secure Vault** | Production | Retrieve at runtime |
1240
-
1241
- ### Environment Variable Names
1242
-
1243
- **Format:** `{PROVIDER}_{TYPE}`
1244
-
1245
- Examples:
1246
- - `GMAIL_ACCESS_TOKEN`
1247
- - `GITHUB_API_KEY`
1248
- - `SLACK_BOT_TOKEN`
1249
-
1250
- **Fallback:** Direct name without `` prefix
1251
-
1252
- ### Security Checklist
1253
-
1254
- - [ ] **Storage**: Never hardcode tokens in source code
1255
- - [ ] **Files**: Add `.env` to `.gitignore`
1256
- - [ ] **Logging**: Never log tokens or include in error messages
1257
- - [ ] **Scope**: Request minimum required permissions only
1258
- - [ ] **Expiration**: Monitor token expiry and refresh periodically
1259
- - [ ] **Rotation**: Rotate tokens regularly (recommend: monthly)
1260
- - [ ] **Revocation**: Revoke tokens when no longer needed
1261
- - [ ] **Transmission**: Always use HTTPS/TLS for requests
1262
-
1263
- ## Troubleshooting
1264
-
1265
- ### Common Issues
1266
-
1267
- | Symptom | Cause | Solution |
1268
- |---------|-------|----------|
1269
- | "Missing required parameter: GMAIL_ACCESS_TOKEN" | Token env var not set | `export GMAIL_ACCESS_TOKEN=token` |
1270
- | "401 Unauthorized" | Invalid or expired token | Refresh token or re-authenticate |
1271
- | "403 Forbidden" | Insufficient scopes | Check token has required permissions |
1272
- | "400 Bad Request" | Malformed request | Verify parameter encoding and URL |
1273
- | "Invalid grant" | Token not recognized | Token revoked or never issued |
1274
- | "Token expired" | Access token lifetime exceeded | Refresh token (Phase 2 feature) |
1275
- | Tool not found | Tool YAML doesn't exist | Verify `tools/{provider}/{tool}.yaml` |
1276
- | Parameter mismatch | User param doesn't match schema | Check tool's parameter definitions |
1277
-
1278
- ### Debug Steps
1279
-
1280
- ```typescript
1281
- // 1. Check env var is set
1282
- console.log(process.env.GMAIL_ACCESS_TOKEN);
1283
-
1284
- // 2. Check parameter name contains TOKEN/KEY/SECRET
1285
- const tool = tools.find(t => t.name === 'send-email');
1286
- console.log(tool.execution);
1287
-
1288
- // 3. Verify token format and expiration
1289
- // Access tokens typically valid for 1 hour
1290
-
1291
- // 4. Test with explicit token override
1292
- await matimo.execute('send-email', {
1293
- to: 'user@example.com',
1294
- subject: 'Test',
1295
- body: 'Test',
1296
- GMAIL_ACCESS_TOKEN: 'explicit-token' // Bypass env lookup
1297
- });
1298
-
1299
- // 5. Check token has required scopes
1300
- // Different tools need different scopes
1301
- ```
1302
-
1303
- ### Token Expiration & Refresh
1304
-
1305
- ```typescript
1306
- // Token expires after ~1 hour
1307
- // Options until Phase 2 auto-refresh:
1308
-
1309
- // Option 1: Refresh using OAuth library
1310
- const newToken = await oauth2.refreshToken(refreshToken);
1311
- process.env.GMAIL_ACCESS_TOKEN = newToken;
1312
-
1313
- // Option 2: Re-authenticate at OAuth Playground
1314
- // Visit: https://developers.google.com/oauthplayground
1315
- // Copy fresh token to env var
1316
-
1317
- // Option 3: Implement token refresh logic in your code
1318
- async function ensureValidToken() {
1319
- const token = process.env.GMAIL_ACCESS_TOKEN;
1320
- if (isExpired(token)) {
1321
- const newToken = await refreshToken();
1322
- process.env.GMAIL_ACCESS_TOKEN = newToken;
1323
- }
1324
- return token;
1325
- }
1326
- ```
1327
-
1328
- ## Adding New Providers
1329
-
1330
- To add support for a new provider (GitHub, Slack, etc.):
1331
-
1332
- 1. **Create Provider Config** - `tools/{provider}/definition.yaml`
1333
- ```yaml
1334
- provider:
1335
- name: github
1336
- oauth2:
1337
- auth_url: https://github.com/login/oauth/authorize
1338
- token_url: https://github.com/login/oauth/access_token
1339
- scopes:
1340
- - repo
1341
- - admin:user
1342
- ```
1343
-
1344
- 2. **Create Tool Definitions** - `tools/{provider}/{tool}.yaml`
1345
- ```yaml
1346
- authentication:
1347
- type: oauth2
1348
- provider: github
1349
- required_scopes: [repo]
1350
- execution:
1351
- headers:
1352
- Authorization: "Bearer {GITHUB_API_KEY}"
1353
- ```
1354
-
1355
- 3. **Set Environment Variable** - `export GITHUB_API_KEY=token`
1356
-
1357
- 4. **Load & Execute** - No code changes needed!
1358
- ```typescript
1359
- const result = await matimo.execute('get-repo', {...});
1360
- ```
1361
-
1362
- ---
1363
-
1364
- **Last Updated:** February 2, 2026
1365
- **Matimo Phase:** 1 (OAuth2 provider config and token injection)
1366
- **Next Phase:** Phase 2 - Automatic token refresh, secure storage, built-in OAuth flows