This is page 3 of 3. Use http://codebase.md/nylas-samples/nylas-api-mcp?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTION.md ├── nylas-code-samples │ ├── Auth │ │ ├── AdminConsent-Bulk │ │ │ └── index.md │ │ ├── AppPermission-Bulk │ │ │ └── index.md │ │ ├── auth.md │ │ ├── connected-accounts.md │ │ ├── Connectors │ │ │ ├── ews.md │ │ │ ├── google.md │ │ │ ├── icloud.md │ │ │ ├── imap.md │ │ │ ├── index.md │ │ │ ├── ms.md │ │ │ ├── virtual-cal.md │ │ │ └── yahoo.md │ │ ├── Hosted │ │ │ └── index.md │ │ ├── Native-Custom │ │ │ ├── index.md │ │ │ └── virtual-cals-custom.md │ │ └── Providers │ │ ├── google-imported.md │ │ ├── google-pubsub.md │ │ ├── google.md │ │ ├── ms-imported.md │ │ └── ms.md │ ├── Calendar │ │ ├── Availability │ │ │ └── index.md │ │ ├── calendar-apis.md │ │ ├── Calendars │ │ │ ├── index.md │ │ │ ├── read.md │ │ │ ├── webhooks.md │ │ │ └── write.md │ │ ├── Events │ │ │ ├── index.md │ │ │ ├── read.md │ │ │ ├── webhooks.md │ │ │ └── write.md │ │ ├── google.md │ │ ├── ms.md │ │ ├── Recurring │ │ │ └── index.md │ │ └── Virtual-Calendars │ │ └── index.md │ ├── Coda │ │ ├── index.md │ │ ├── testing.md │ │ └── webhooks.md │ ├── Contacts │ │ ├── index.md │ │ ├── read.md │ │ ├── webhooks.md │ │ └── write.md │ ├── Email │ │ ├── Drafts │ │ │ ├── index.md │ │ │ ├── read.md │ │ │ └── write.md │ │ ├── Files-Attachments │ │ │ ├── index.md │ │ │ └── read.md │ │ ├── Labels-Folders │ │ │ ├── index.md │ │ │ ├── read.md │ │ │ ├── webhooks.md │ │ │ └── write.md │ │ ├── Messages │ │ │ ├── index.md │ │ │ ├── read.md │ │ │ ├── webhooks.md │ │ │ └── write.md │ │ ├── Outbox │ │ │ ├── index.md │ │ │ ├── read.md │ │ │ ├── webhooks.md │ │ │ └── write.md │ │ ├── Search │ │ │ ├── index.md │ │ │ └── read.md │ │ ├── Threads │ │ │ ├── index.md │ │ │ ├── read.md │ │ │ ├── webhooks.md │ │ │ └── write.md │ │ └── Tracking │ │ ├── index.md │ │ └── webhooks.md │ ├── Start │ │ ├── api-import.md │ │ ├── Dashboard-Import │ │ │ └── index.md │ │ ├── index.md │ │ └── manual.md │ └── Webhooks │ ├── index.md │ └── new-pubsub-note.md ├── package-lock.json ├── package.json ├── README.md ├── src │ ├── index.ts │ ├── prompts │ │ └── index.ts │ ├── resources │ │ ├── code-samples.ts │ │ ├── docs.ts │ │ ├── endpoints.ts │ │ └── index.ts │ └── tools │ └── index.ts └── tsconfig.json ``` # Files -------------------------------------------------------------------------------- /src/resources/endpoints.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; 2 | 3 | /** 4 | * Register resources for Nylas API endpoints 5 | */ 6 | export function registerEndpointResources(server: McpServer) { 7 | // Register a resource that lists all available endpoints 8 | server.resource( 9 | "nylas-endpoints", 10 | "nylas://endpoints", 11 | async (uri) => ({ 12 | contents: [{ 13 | uri: uri.href, 14 | text: `# Nylas API Endpoints 15 | 16 | This resource provides documentation for Nylas API endpoints organized by category. 17 | 18 | ## Authentication 19 | 20 | - [Authentication](nylas://endpoints/auth) 21 | - [Connected Accounts](nylas://endpoints/connected-accounts) 22 | 23 | ## Email 24 | 25 | - [Messages](nylas://endpoints/messages) 26 | - [Threads](nylas://endpoints/threads) 27 | - [Drafts](nylas://endpoints/drafts) 28 | - [Files & Attachments](nylas://endpoints/attachments) 29 | - [Folders & Labels](nylas://endpoints/folders) 30 | - [Search](nylas://endpoints/search) 31 | 32 | ## Calendar 33 | 34 | - [Calendars](nylas://endpoints/calendars) 35 | - [Events](nylas://endpoints/events) 36 | - [Availability](nylas://endpoints/availability) 37 | - [Free/Busy](nylas://endpoints/free-busy) 38 | 39 | ## Contacts 40 | 41 | - [Contacts](nylas://endpoints/contacts) 42 | 43 | ## Webhooks 44 | 45 | - [Webhooks](nylas://endpoints/webhooks)`, 46 | mimeType: "text/markdown" 47 | }] 48 | }) 49 | ); 50 | 51 | // Register a resource for specific endpoint categories 52 | server.resource( 53 | "endpoint-category", 54 | new ResourceTemplate("nylas://endpoints/{category}", { list: undefined }), 55 | async (uri, { category }) => { 56 | // Convert category to string if it's an array 57 | const categoryStr = typeof category === 'string' ? category : category[0]; 58 | 59 | // Map of categories to their endpoint documentation 60 | const categories: Record<string, string> = { 61 | "messages": `# Messages Endpoints 62 | 63 | ## Overview 64 | 65 | The Messages endpoints allow you to read, send, and manage email messages. 66 | 67 | ## Endpoints 68 | 69 | ### List Messages 70 | 71 | \`GET /v3/grants/{grant_id}/messages\` 72 | 73 | Retrieves a list of messages from a user's mailbox. 74 | 75 | **Parameters:** 76 | - \`grant_id\` (path): The ID of the grant 77 | - \`limit\` (query): Maximum number of messages to return (default: 10, max: 100) 78 | - \`offset\` (query): Pagination offset 79 | - \`sort\` (query): Sort order (default: "-date") 80 | - \`view\` (query): View type ("ids", "count", "expanded") 81 | - \`thread_id\` (query): Filter by thread ID 82 | - \`received_after\` (query): Filter by received date (Unix timestamp) 83 | - \`received_before\` (query): Filter by received date (Unix timestamp) 84 | - \`in\` (query): Filter by folder/label ID 85 | 86 | **Response:** 87 | - \`data\`: Array of message objects 88 | - \`next_cursor\`: Cursor for pagination 89 | - \`has_more\`: Boolean indicating if more results exist 90 | 91 | ### Get Message 92 | 93 | \`GET /v3/grants/{grant_id}/messages/{message_id}\` 94 | 95 | Retrieves a specific message by ID. 96 | 97 | **Parameters:** 98 | - \`grant_id\` (path): The ID of the grant 99 | - \`message_id\` (path): The ID of the message 100 | 101 | **Response:** 102 | - Message object with full details 103 | 104 | ### Send Message 105 | 106 | \`POST /v3/grants/{grant_id}/messages\` 107 | 108 | Sends a new email message. 109 | 110 | **Parameters:** 111 | - \`grant_id\` (path): The ID of the grant 112 | 113 | **Request Body:** 114 | - \`subject\`: Email subject 115 | - \`to\`: Array of recipient objects 116 | - \`cc\` (optional): Array of CC recipient objects 117 | - \`bcc\` (optional): Array of BCC recipient objects 118 | - \`body\`: Email body content 119 | - \`file_ids\` (optional): Array of file IDs to attach 120 | 121 | **Response:** 122 | - Created message object 123 | 124 | ### Update Message 125 | 126 | \`PUT /v3/grants/{grant_id}/messages/{message_id}\` 127 | 128 | Updates a message's properties. 129 | 130 | **Parameters:** 131 | - \`grant_id\` (path): The ID of the grant 132 | - \`message_id\` (path): The ID of the message 133 | 134 | **Request Body:** 135 | - \`unread\` (optional): Boolean indicating read/unread state 136 | - \`starred\` (optional): Boolean indicating starred state 137 | - \`folder_id\` (optional): ID of the folder to move the message to 138 | 139 | **Response:** 140 | - Updated message object 141 | 142 | ### Delete Message 143 | 144 | \`DELETE /v3/grants/{grant_id}/messages/{message_id}\` 145 | 146 | Moves a message to the trash folder. 147 | 148 | **Parameters:** 149 | - \`grant_id\` (path): The ID of the grant 150 | - \`message_id\` (path): The ID of the message 151 | 152 | **Response:** 153 | - \`status\`: Success status`, 154 | 155 | "threads": `# Threads Endpoints 156 | 157 | ## Overview 158 | 159 | The Threads endpoints allow you to read and manage email threads (conversations). 160 | 161 | ## Endpoints 162 | 163 | ### List Threads 164 | 165 | \`GET /v3/grants/{grant_id}/threads\` 166 | 167 | Retrieves a list of threads from a user's mailbox. 168 | 169 | **Parameters:** 170 | - \`grant_id\` (path): The ID of the grant 171 | - \`limit\` (query): Maximum number of threads to return (default: 10, max: 100) 172 | - \`offset\` (query): Pagination offset 173 | - \`view\` (query): View type ("ids", "count", "expanded") 174 | - \`received_after\` (query): Filter by received date (Unix timestamp) 175 | - \`received_before\` (query): Filter by received date (Unix timestamp) 176 | - \`in\` (query): Filter by folder/label ID 177 | 178 | **Response:** 179 | - \`data\`: Array of thread objects 180 | - \`next_cursor\`: Cursor for pagination 181 | - \`has_more\`: Boolean indicating if more results exist 182 | 183 | ### Get Thread 184 | 185 | \`GET /v3/grants/{grant_id}/threads/{thread_id}\` 186 | 187 | Retrieves a specific thread by ID. 188 | 189 | **Parameters:** 190 | - \`grant_id\` (path): The ID of the grant 191 | - \`thread_id\` (path): The ID of the thread 192 | 193 | **Response:** 194 | - Thread object with full details including messages 195 | 196 | ### Update Thread 197 | 198 | \`PUT /v3/grants/{grant_id}/threads/{thread_id}\` 199 | 200 | Updates a thread's properties. 201 | 202 | **Parameters:** 203 | - \`grant_id\` (path): The ID of the grant 204 | - \`thread_id\` (path): The ID of the thread 205 | 206 | **Request Body:** 207 | - \`unread\` (optional): Boolean indicating read/unread state 208 | - \`starred\` (optional): Boolean indicating starred state 209 | - \`folder_id\` (optional): ID of the folder to move the thread to 210 | 211 | **Response:** 212 | - Updated thread object`, 213 | 214 | "drafts": `# Drafts Endpoints 215 | 216 | ## Overview 217 | 218 | The Drafts endpoints allow you to create, read, update, and send email drafts. 219 | 220 | ## Endpoints 221 | 222 | ### List Drafts 223 | 224 | \`GET /v3/grants/{grant_id}/drafts\` 225 | 226 | Retrieves a list of drafts from a user's mailbox. 227 | 228 | **Parameters:** 229 | - \`grant_id\` (path): The ID of the grant 230 | - \`limit\` (query): Maximum number of drafts to return (default: 10, max: 100) 231 | - \`offset\` (query): Pagination offset 232 | 233 | **Response:** 234 | - \`data\`: Array of draft objects 235 | - \`next_cursor\`: Cursor for pagination 236 | - \`has_more\`: Boolean indicating if more results exist 237 | 238 | ### Get Draft 239 | 240 | \`GET /v3/grants/{grant_id}/drafts/{draft_id}\` 241 | 242 | Retrieves a specific draft by ID. 243 | 244 | **Parameters:** 245 | - \`grant_id\` (path): The ID of the grant 246 | - \`draft_id\` (path): The ID of the draft 247 | 248 | **Response:** 249 | - Draft object with full details 250 | 251 | ### Create Draft 252 | 253 | \`POST /v3/grants/{grant_id}/drafts\` 254 | 255 | Creates a new email draft. 256 | 257 | **Parameters:** 258 | - \`grant_id\` (path): The ID of the grant 259 | 260 | **Request Body:** 261 | - \`subject\`: Email subject 262 | - \`to\` (optional): Array of recipient objects 263 | - \`cc\` (optional): Array of CC recipient objects 264 | - \`bcc\` (optional): Array of BCC recipient objects 265 | - \`body\` (optional): Email body content 266 | - \`file_ids\` (optional): Array of file IDs to attach 267 | 268 | **Response:** 269 | - Created draft object 270 | 271 | ### Update Draft 272 | 273 | \`PUT /v3/grants/{grant_id}/drafts/{draft_id}\` 274 | 275 | Updates an existing draft. 276 | 277 | **Parameters:** 278 | - \`grant_id\` (path): The ID of the grant 279 | - \`draft_id\` (path): The ID of the draft 280 | 281 | **Request Body:** 282 | - \`subject\` (optional): Email subject 283 | - \`to\` (optional): Array of recipient objects 284 | - \`cc\` (optional): Array of CC recipient objects 285 | - \`bcc\` (optional): Array of BCC recipient objects 286 | - \`body\` (optional): Email body content 287 | - \`file_ids\` (optional): Array of file IDs to attach 288 | 289 | **Response:** 290 | - Updated draft object 291 | 292 | ### Delete Draft 293 | 294 | \`DELETE /v3/grants/{grant_id}/drafts/{draft_id}\` 295 | 296 | Deletes a draft. 297 | 298 | **Parameters:** 299 | - \`grant_id\` (path): The ID of the grant 300 | - \`draft_id\` (path): The ID of the draft 301 | 302 | **Response:** 303 | - \`status\`: Success status 304 | 305 | ### Send Draft 306 | 307 | \`POST /v3/grants/{grant_id}/drafts/{draft_id}/send\` 308 | 309 | Sends an existing draft. 310 | 311 | **Parameters:** 312 | - \`grant_id\` (path): The ID of the grant 313 | - \`draft_id\` (path): The ID of the draft 314 | 315 | **Response:** 316 | - Sent message object`, 317 | 318 | "attachments": `# Files & Attachments Endpoints 319 | 320 | ## Overview 321 | 322 | The Files & Attachments endpoints allow you to upload, download, and manage files attached to emails. 323 | 324 | ## Endpoints 325 | 326 | ### List Files 327 | 328 | \`GET /v3/grants/{grant_id}/files\` 329 | 330 | Retrieves a list of files attached to emails. 331 | 332 | **Parameters:** 333 | - \`grant_id\` (path): The ID of the grant 334 | - \`limit\` (query): Maximum number of files to return (default: 10, max: 100) 335 | - \`offset\` (query): Pagination offset 336 | - \`message_id\` (query): Filter by message ID 337 | 338 | **Response:** 339 | - \`data\`: Array of file objects 340 | - \`next_cursor\`: Cursor for pagination 341 | - \`has_more\`: Boolean indicating if more results exist 342 | 343 | ### Get File 344 | 345 | \`GET /v3/grants/{grant_id}/files/{file_id}\` 346 | 347 | Retrieves metadata for a specific file. 348 | 349 | **Parameters:** 350 | - \`grant_id\` (path): The ID of the grant 351 | - \`file_id\` (path): The ID of the file 352 | 353 | **Response:** 354 | - File object with metadata 355 | 356 | ### Download File 357 | 358 | \`GET /v3/grants/{grant_id}/files/{file_id}/download\` 359 | 360 | Downloads the content of a file. 361 | 362 | **Parameters:** 363 | - \`grant_id\` (path): The ID of the grant 364 | - \`file_id\` (path): The ID of the file 365 | 366 | **Response:** 367 | - Binary file content with appropriate Content-Type header 368 | 369 | ### Upload File 370 | 371 | \`POST /v3/grants/{grant_id}/files\` 372 | 373 | Uploads a new file to be attached to emails. 374 | 375 | **Parameters:** 376 | - \`grant_id\` (path): The ID of the grant 377 | 378 | **Request Body:** 379 | - Multipart form data with file content 380 | 381 | **Response:** 382 | - Uploaded file object with ID for attachment`, 383 | 384 | "folders": `# Folders & Labels Endpoints 385 | 386 | ## Overview 387 | 388 | The Folders & Labels endpoints allow you to manage email organization structures. 389 | 390 | ## Endpoints 391 | 392 | ### List Folders 393 | 394 | \`GET /v3/grants/{grant_id}/folders\` 395 | 396 | Retrieves a list of folders from a user's mailbox. 397 | 398 | **Parameters:** 399 | - \`grant_id\` (path): The ID of the grant 400 | 401 | **Response:** 402 | - \`data\`: Array of folder objects 403 | 404 | ### Get Folder 405 | 406 | \`GET /v3/grants/{grant_id}/folders/{folder_id}\` 407 | 408 | Retrieves a specific folder by ID. 409 | 410 | **Parameters:** 411 | - \`grant_id\` (path): The ID of the grant 412 | - \`folder_id\` (path): The ID of the folder 413 | 414 | **Response:** 415 | - Folder object with details 416 | 417 | ### Create Folder 418 | 419 | \`POST /v3/grants/{grant_id}/folders\` 420 | 421 | Creates a new folder. 422 | 423 | **Parameters:** 424 | - \`grant_id\` (path): The ID of the grant 425 | 426 | **Request Body:** 427 | - \`name\`: Folder name 428 | - \`parent_id\` (optional): Parent folder ID for nested folders 429 | 430 | **Response:** 431 | - Created folder object 432 | 433 | ### Update Folder 434 | 435 | \`PUT /v3/grants/{grant_id}/folders/{folder_id}\` 436 | 437 | Updates a folder's properties. 438 | 439 | **Parameters:** 440 | - \`grant_id\` (path): The ID of the grant 441 | - \`folder_id\` (path): The ID of the folder 442 | 443 | **Request Body:** 444 | - \`name\` (optional): New folder name 445 | - \`parent_id\` (optional): New parent folder ID 446 | 447 | **Response:** 448 | - Updated folder object 449 | 450 | ### Delete Folder 451 | 452 | \`DELETE /v3/grants/{grant_id}/folders/{folder_id}\` 453 | 454 | Deletes a folder. 455 | 456 | **Parameters:** 457 | - \`grant_id\` (path): The ID of the grant 458 | - \`folder_id\` (path): The ID of the folder 459 | 460 | **Response:** 461 | - \`status\`: Success status`, 462 | 463 | "search": `# Search Endpoints 464 | 465 | ## Overview 466 | 467 | The Search endpoints allow you to search for emails by various criteria. 468 | 469 | ## Endpoints 470 | 471 | ### Search Messages 472 | 473 | \`GET /v3/grants/{grant_id}/messages/search\` 474 | 475 | Searches for messages matching specific criteria. 476 | 477 | **Parameters:** 478 | - \`grant_id\` (path): The ID of the grant 479 | - \`q\` (query): Search query string 480 | - \`limit\` (query): Maximum number of results to return (default: 10, max: 100) 481 | - \`offset\` (query): Pagination offset 482 | - \`in\` (query): Filter by folder/label ID 483 | - \`date_gt\` (query): Filter by date greater than (Unix timestamp) 484 | - \`date_lt\` (query): Filter by date less than (Unix timestamp) 485 | 486 | **Response:** 487 | - \`data\`: Array of matching message objects 488 | - \`next_cursor\`: Cursor for pagination 489 | - \`has_more\`: Boolean indicating if more results exist 490 | 491 | ### Search Threads 492 | 493 | \`GET /v3/grants/{grant_id}/threads/search\` 494 | 495 | Searches for threads matching specific criteria. 496 | 497 | **Parameters:** 498 | - \`grant_id\` (path): The ID of the grant 499 | - \`q\` (query): Search query string 500 | - \`limit\` (query): Maximum number of results to return (default: 10, max: 100) 501 | - \`offset\` (query): Pagination offset 502 | - \`in\` (query): Filter by folder/label ID 503 | - \`date_gt\` (query): Filter by date greater than (Unix timestamp) 504 | - \`date_lt\` (query): Filter by date less than (Unix timestamp) 505 | 506 | **Response:** 507 | - \`data\`: Array of matching thread objects 508 | - \`next_cursor\`: Cursor for pagination 509 | - \`has_more\`: Boolean indicating if more results exist`, 510 | 511 | "calendars": `# Calendars Endpoints 512 | 513 | ## Overview 514 | 515 | The Calendars endpoints allow you to read and manage calendar containers. 516 | 517 | ## Endpoints 518 | 519 | ### List Calendars 520 | 521 | \`GET /v3/grants/{grant_id}/calendars\` 522 | 523 | Retrieves a list of calendars for a user. 524 | 525 | **Parameters:** 526 | - \`grant_id\` (path): The ID of the grant 527 | 528 | **Response:** 529 | - \`data\`: Array of calendar objects 530 | 531 | ### Get Calendar 532 | 533 | \`GET /v3/grants/{grant_id}/calendars/{calendar_id}\` 534 | 535 | Retrieves a specific calendar by ID. 536 | 537 | **Parameters:** 538 | - \`grant_id\` (path): The ID of the grant 539 | - \`calendar_id\` (path): The ID of the calendar 540 | 541 | **Response:** 542 | - Calendar object with details 543 | 544 | ### Create Calendar 545 | 546 | \`POST /v3/grants/{grant_id}/calendars\` 547 | 548 | Creates a new calendar. 549 | 550 | **Parameters:** 551 | - \`grant_id\` (path): The ID of the grant 552 | 553 | **Request Body:** 554 | - \`name\`: Calendar name 555 | - \`description\` (optional): Calendar description 556 | - \`location\` (optional): Calendar location 557 | - \`timezone\` (optional): Calendar timezone 558 | - \`metadata\` (optional): Custom metadata 559 | 560 | **Response:** 561 | - Created calendar object 562 | 563 | ### Update Calendar 564 | 565 | \`PUT /v3/grants/{grant_id}/calendars/{calendar_id}\` 566 | 567 | Updates a calendar's properties. 568 | 569 | **Parameters:** 570 | - \`grant_id\` (path): The ID of the grant 571 | - \`calendar_id\` (path): The ID of the calendar 572 | 573 | **Request Body:** 574 | - \`name\` (optional): New calendar name 575 | - \`description\` (optional): New calendar description 576 | - \`location\` (optional): New calendar location 577 | - \`timezone\` (optional): New calendar timezone 578 | - \`metadata\` (optional): Updated custom metadata 579 | 580 | **Response:** 581 | - Updated calendar object 582 | 583 | ### Delete Calendar 584 | 585 | \`DELETE /v3/grants/{grant_id}/calendars/{calendar_id}\` 586 | 587 | Deletes a calendar. 588 | 589 | **Parameters:** 590 | - \`grant_id\` (path): The ID of the grant 591 | - \`calendar_id\` (path): The ID of the calendar 592 | 593 | **Response:** 594 | - \`status\`: Success status`, 595 | 596 | "events": `# Events Endpoints 597 | 598 | ## Overview 599 | 600 | The Events endpoints allow you to read, create, update, and delete calendar events. 601 | 602 | ## Endpoints 603 | 604 | ### List Events 605 | 606 | \`GET /v3/grants/{grant_id}/events\` 607 | 608 | Retrieves a list of events from a user's calendars. 609 | 610 | **Parameters:** 611 | - \`grant_id\` (path): The ID of the grant 612 | - \`calendar_id\` (query): Filter by calendar ID 613 | - \`limit\` (query): Maximum number of events to return (default: 10, max: 100) 614 | - \`offset\` (query): Pagination offset 615 | - \`start_time\` (query): Filter by start time (Unix timestamp) 616 | - \`end_time\` (query): Filter by end time (Unix timestamp) 617 | - \`show_cancelled\` (query): Include cancelled events (default: false) 618 | 619 | **Response:** 620 | - \`data\`: Array of event objects 621 | - \`next_cursor\`: Cursor for pagination 622 | - \`has_more\`: Boolean indicating if more results exist 623 | 624 | ### Get Event 625 | 626 | \`GET /v3/grants/{grant_id}/events/{event_id}\` 627 | 628 | Retrieves a specific event by ID. 629 | 630 | **Parameters:** 631 | - \`grant_id\` (path): The ID of the grant 632 | - \`event_id\` (path): The ID of the event 633 | 634 | **Response:** 635 | - Event object with full details 636 | 637 | ### Create Event 638 | 639 | \`POST /v3/grants/{grant_id}/events\` 640 | 641 | Creates a new calendar event. 642 | 643 | **Parameters:** 644 | - \`grant_id\` (path): The ID of the grant 645 | 646 | **Request Body:** 647 | - \`calendar_id\`: Calendar ID to create the event in 648 | - \`title\`: Event title 649 | - \`start_time\`: Event start time (Unix timestamp) 650 | - \`end_time\`: Event end time (Unix timestamp) 651 | - \`description\` (optional): Event description 652 | - \`location\` (optional): Event location 653 | - \`participants\` (optional): Array of participant objects 654 | - \`conferencing\` (optional): Conferencing details 655 | - \`busy\` (optional): Whether the event shows as busy (default: true) 656 | - \`reminders\` (optional): Array of reminder objects 657 | - \`recurrence\` (optional): Recurrence rule 658 | 659 | **Response:** 660 | - Created event object 661 | 662 | ### Update Event 663 | 664 | \`PUT /v3/grants/{grant_id}/events/{event_id}\` 665 | 666 | Updates an existing event. 667 | 668 | **Parameters:** 669 | - \`grant_id\` (path): The ID of the grant 670 | - \`event_id\` (path): The ID of the event 671 | 672 | **Request Body:** 673 | - \`calendar_id\` (optional): Calendar ID to move the event to 674 | - \`title\` (optional): New event title 675 | - \`start_time\` (optional): New event start time (Unix timestamp) 676 | - \`end_time\` (optional): New event end time (Unix timestamp) 677 | - \`description\` (optional): New event description 678 | - \`location\` (optional): New event location 679 | - \`participants\` (optional): Updated array of participant objects 680 | - \`conferencing\` (optional): Updated conferencing details 681 | - \`busy\` (optional): Whether the event shows as busy 682 | - \`reminders\` (optional): Updated array of reminder objects 683 | - \`recurrence\` (optional): Updated recurrence rule 684 | 685 | **Response:** 686 | - Updated event object 687 | 688 | ### Delete Event 689 | 690 | \`DELETE /v3/grants/{grant_id}/events/{event_id}\` 691 | 692 | Deletes an event. 693 | 694 | **Parameters:** 695 | - \`grant_id\` (path): The ID of the grant 696 | - \`event_id\` (path): The ID of the event 697 | 698 | **Response:** 699 | - \`status\`: Success status`, 700 | 701 | "availability": `# Availability Endpoints 702 | 703 | ## Overview 704 | 705 | The Availability endpoints allow you to find free/busy information and available times. 706 | 707 | ## Endpoints 708 | 709 | ### Get Availability 710 | 711 | \`POST /v3/grants/{grant_id}/calendars/availability\` 712 | 713 | Finds available time slots across multiple participants' calendars. 714 | 715 | **Parameters:** 716 | - \`grant_id\` (path): The ID of the grant 717 | 718 | **Request Body:** 719 | - \`start_time\`: Start of the time range to check (Unix timestamp) 720 | - \`end_time\`: End of the time range to check (Unix timestamp) 721 | - \`duration_minutes\`: Length of the slots to find 722 | - \`participants\`: Array of participant objects with emails 723 | - \`interval_minutes\` (optional): Interval between potential slots (default: 15) 724 | - \`availability_rule\` (optional): Rule for determining availability ("any" or "all", default: "all") 725 | - \`buffer_minutes\` (optional): Buffer time between meetings (default: 0) 726 | - \`working_hours\` (optional): Working hours constraints 727 | - \`open_hours\` (optional): Open hours constraints 728 | 729 | **Response:** 730 | - \`time_slots\`: Array of available time slot objects 731 | - \`timezone\`: Timezone used for calculations`, 732 | 733 | "free-busy": `# Free/Busy Endpoints 734 | 735 | ## Overview 736 | 737 | The Free/Busy endpoints allow you to check when users are free or busy. 738 | 739 | ## Endpoints 740 | 741 | ### Get Free/Busy 742 | 743 | \`POST /v3/grants/{grant_id}/calendars/free-busy\` 744 | 745 | Retrieves free/busy information for users. 746 | 747 | **Parameters:** 748 | - \`grant_id\` (path): The ID of the grant 749 | 750 | **Request Body:** 751 | - \`start_time\`: Start of the time range to check (Unix timestamp) 752 | - \`end_time\`: End of the time range to check (Unix timestamp) 753 | - \`emails\`: Array of email addresses to check 754 | 755 | **Response:** 756 | - \`free_busy\`: Object mapping emails to arrays of busy time periods`, 757 | 758 | "contacts": `# Contacts Endpoints 759 | 760 | ## Overview 761 | 762 | The Contacts endpoints allow you to read, create, update, and delete contact information. 763 | 764 | ## Endpoints 765 | 766 | ### List Contacts 767 | 768 | \`GET /v3/grants/{grant_id}/contacts\` 769 | 770 | Retrieves a list of contacts. 771 | 772 | **Parameters:** 773 | - \`grant_id\` (path): The ID of the grant 774 | - \`limit\` (query): Maximum number of contacts to return (default: 10, max: 100) 775 | - \`offset\` (query): Pagination offset 776 | - \`email\` (query): Filter by email address 777 | - \`phone_number\` (query): Filter by phone number 778 | - \`source\` (query): Filter by source of the contact 779 | 780 | **Response:** 781 | - \`data\`: Array of contact objects 782 | - \`next_cursor\`: Cursor for pagination 783 | - \`has_more\`: Boolean indicating if more results exist 784 | 785 | ### Get Contact 786 | 787 | \`GET /v3/grants/{grant_id}/contacts/{contact_id}\` 788 | 789 | Retrieves a specific contact by ID. 790 | 791 | **Parameters:** 792 | - \`grant_id\` (path): The ID of the grant 793 | - \`contact_id\` (path): The ID of the contact 794 | 795 | **Response:** 796 | - Contact object with full details 797 | 798 | ### Create Contact 799 | 800 | \`POST /v3/grants/{grant_id}/contacts\` 801 | 802 | Creates a new contact. 803 | 804 | **Parameters:** 805 | - \`grant_id\` (path): The ID of the grant 806 | 807 | **Request Body:** 808 | - \`given_name\` (optional): First name 809 | - \`middle_name\` (optional): Middle name 810 | - \`surname\` (optional): Last name 811 | - \`nickname\` (optional): Nickname 812 | - \`emails\` (optional): Array of email objects 813 | - \`phone_numbers\` (optional): Array of phone number objects 814 | - \`physical_addresses\` (optional): Array of address objects 815 | - \`web_pages\` (optional): Array of web page objects 816 | - \`notes\` (optional): Notes about the contact 817 | - \`job_title\` (optional): Job title 818 | - \`company_name\` (optional): Company name 819 | - \`picture\` (optional): Profile picture URL 820 | - \`birthday\` (optional): Birthday (Unix timestamp) 821 | 822 | **Response:** 823 | - Created contact object 824 | 825 | ### Update Contact 826 | 827 | \`PUT /v3/grants/{grant_id}/contacts/{contact_id}\` 828 | 829 | Updates an existing contact. 830 | 831 | **Parameters:** 832 | - \`grant_id\` (path): The ID of the grant 833 | - \`contact_id\` (path): The ID of the contact 834 | 835 | **Request Body:** 836 | - \`given_name\` (optional): Updated first name 837 | - \`middle_name\` (optional): Updated middle name 838 | - \`surname\` (optional): Updated last name 839 | - \`nickname\` (optional): Updated nickname 840 | - \`emails\` (optional): Updated array of email objects 841 | - \`phone_numbers\` (optional): Updated array of phone number objects 842 | - \`physical_addresses\` (optional): Updated array of address objects 843 | - \`web_pages\` (optional): Updated array of web page objects 844 | - \`notes\` (optional): Updated notes about the contact 845 | - \`job_title\` (optional): Updated job title 846 | - \`company_name\` (optional): Updated company name 847 | - \`picture\` (optional): Updated profile picture URL 848 | - \`birthday\` (optional): Updated birthday (Unix timestamp) 849 | 850 | **Response:** 851 | - Updated contact object 852 | 853 | ### Delete Contact 854 | 855 | \`DELETE /v3/grants/{grant_id}/contacts/{contact_id}\` 856 | 857 | Deletes a contact. 858 | 859 | **Parameters:** 860 | - \`grant_id\` (path): The ID of the grant 861 | - \`contact_id\` (path): The ID of the contact 862 | 863 | **Response:** 864 | - \`status\`: Success status`, 865 | 866 | "webhooks": `# Webhooks Endpoints 867 | 868 | ## Overview 869 | 870 | The Webhooks endpoints allow you to set up real-time notifications for changes to user data. 871 | 872 | ## Endpoints 873 | 874 | ### List Webhooks 875 | 876 | \`GET /v3/applications/{application_id}/webhooks\` 877 | 878 | Retrieves a list of webhooks for an application. 879 | 880 | **Parameters:** 881 | - \`application_id\` (path): The ID of the application 882 | - \`limit\` (query): Maximum number of webhooks to return (default: 10, max: 100) 883 | - \`offset\` (query): Pagination offset 884 | 885 | **Response:** 886 | - \`data\`: Array of webhook objects 887 | - \`next_cursor\`: Cursor for pagination 888 | - \`has_more\`: Boolean indicating if more results exist 889 | 890 | ### Get Webhook 891 | 892 | \`GET /v3/applications/{application_id}/webhooks/{webhook_id}\` 893 | 894 | Retrieves a specific webhook by ID. 895 | 896 | **Parameters:** 897 | - \`application_id\` (path): The ID of the application 898 | - \`webhook_id\` (path): The ID of the webhook 899 | 900 | **Response:** 901 | - Webhook object with full details 902 | 903 | ### Create Webhook 904 | 905 | \`POST /v3/applications/{application_id}/webhooks\` 906 | 907 | Creates a new webhook. 908 | 909 | **Parameters:** 910 | - \`application_id\` (path): The ID of the application 911 | 912 | **Request Body:** 913 | - \`webhook_url\`: URL to send webhook events to 914 | - \`description\` (optional): Description of the webhook 915 | - \`trigger_types\`: Array of event types to trigger the webhook 916 | - \`webhook_secret\` (optional): Secret for securing webhook payloads 917 | - \`grant_id\` (optional): Specific grant ID to monitor (omit for all grants) 918 | 919 | **Response:** 920 | - Created webhook object 921 | 922 | ### Update Webhook 923 | 924 | \`PUT /v3/applications/{application_id}/webhooks/{webhook_id}\` 925 | 926 | Updates an existing webhook. 927 | 928 | **Parameters:** 929 | - \`application_id\` (path): The ID of the application 930 | - \`webhook_id\` (path): The ID of the webhook 931 | 932 | **Request Body:** 933 | - \`webhook_url\` (optional): Updated URL to send webhook events to 934 | - \`description\` (optional): Updated description of the webhook 935 | - \`trigger_types\` (optional): Updated array of event types to trigger the webhook 936 | - \`webhook_secret\` (optional): Updated secret for securing webhook payloads 937 | - \`status\` (optional): Updated status ("active" or "disabled") 938 | 939 | **Response:** 940 | - Updated webhook object 941 | 942 | ### Delete Webhook 943 | 944 | \`DELETE /v3/applications/{application_id}/webhooks/{webhook_id}\` 945 | 946 | Deletes a webhook. 947 | 948 | **Parameters:** 949 | - \`application_id\` (path): The ID of the application 950 | - \`webhook_id\` (path): The ID of the webhook 951 | 952 | **Response:** 953 | - \`status\`: Success status 954 | 955 | ### Rotate Webhook Secret 956 | 957 | \`POST /v3/applications/{application_id}/webhooks/{webhook_id}/rotate-secret\` 958 | 959 | Generates a new secret for a webhook. 960 | 961 | **Parameters:** 962 | - \`application_id\` (path): The ID of the application 963 | - \`webhook_id\` (path): The ID of the webhook 964 | 965 | **Response:** 966 | - \`webhook_secret\`: The new webhook secret`, 967 | 968 | "auth": `# Authentication Endpoints 969 | 970 | ## Overview 971 | 972 | The Authentication endpoints allow you to initiate the OAuth flow and manage authentication tokens. 973 | 974 | ## Endpoints 975 | 976 | ### Generate Authentication URL 977 | 978 | \`GET /v3/connect/oauth/authorize\` 979 | 980 | Generates a URL to redirect users to for authentication. 981 | 982 | **Parameters:** 983 | - \`client_id\` (query): Your application's client ID 984 | - \`redirect_uri\` (query): URL to redirect to after authentication 985 | - \`response_type\` (query): Authentication response type (default: "code") 986 | - \`scopes\` (query): Comma-separated list of permission scopes 987 | - \`state\` (query): Optional state parameter for security 988 | - \`provider\` (query, optional): Email provider ("google", "microsoft", etc.) 989 | - \`login_hint\` (query, optional): User's email address for pre-filling 990 | 991 | **Response:** 992 | - Redirect to the authentication URL 993 | 994 | ### Exchange Code for Token 995 | 996 | \`POST /v3/connect/oauth/token\` 997 | 998 | Exchanges an authentication code for an access token. 999 | 1000 | **Request Body:** 1001 | - \`client_id\`: Your application's client ID 1002 | - \`client_secret\`: Your application's client secret 1003 | - \`grant_type\`: Type of grant (use "authorization_code") 1004 | - \`code\`: The authorization code received from the redirect 1005 | - \`redirect_uri\`: The same redirect URI used in the authorization request 1006 | 1007 | **Response:** 1008 | - \`access_token\`: The access token for API requests 1009 | - \`token_type\`: Type of token (usually "bearer") 1010 | - \`expires_in\`: Time until token expiration (in seconds) 1011 | - \`refresh_token\`: Token for obtaining a new access token 1012 | - \`scope\`: Granted permission scopes 1013 | - \`grant_id\`: ID of the newly created grant 1014 | 1015 | ### Refresh Token 1016 | 1017 | \`POST /v3/connect/oauth/token\` 1018 | 1019 | Refreshes an expired access token. 1020 | 1021 | **Request Body:** 1022 | - \`client_id\`: Your application's client ID 1023 | - \`client_secret\`: Your application's client secret 1024 | - \`grant_type\`: Type of grant (use "refresh_token") 1025 | - \`refresh_token\`: The refresh token received previously 1026 | 1027 | **Response:** 1028 | - \`access_token\`: New access token for API requests 1029 | - \`token_type\`: Type of token (usually "bearer") 1030 | - \`expires_in\`: Time until token expiration (in seconds) 1031 | - \`refresh_token\`: New refresh token 1032 | - \`scope\`: Granted permission scopes`, 1033 | 1034 | "connected-accounts": `# Connected Accounts Endpoints 1035 | 1036 | ## Overview 1037 | 1038 | The Connected Accounts endpoints allow you to manage user accounts connected to your application. 1039 | 1040 | ## Endpoints 1041 | 1042 | ### List Grants 1043 | 1044 | \`GET /v3/applications/{application_id}/grants\` 1045 | 1046 | Retrieves a list of grants (connected accounts) for your application. 1047 | 1048 | **Parameters:** 1049 | - \`application_id\` (path): The ID of your application 1050 | - \`limit\` (query): Maximum number of grants to return (default: 10, max: 100) 1051 | - \`offset\` (query): Pagination offset 1052 | - \`provider\` (query, optional): Filter by provider 1053 | - \`email\` (query, optional): Filter by email address 1054 | 1055 | **Response:** 1056 | - \`data\`: Array of grant objects 1057 | - \`next_cursor\`: Cursor for pagination 1058 | - \`has_more\`: Boolean indicating if more results exist 1059 | 1060 | ### Get Grant 1061 | 1062 | \`GET /v3/applications/{application_id}/grants/{grant_id}\` 1063 | 1064 | Retrieves a specific grant by ID. 1065 | 1066 | **Parameters:** 1067 | - \`application_id\` (path): The ID of your application 1068 | - \`grant_id\` (path): The ID of the grant 1069 | 1070 | **Response:** 1071 | - Grant object with full details 1072 | 1073 | ### Delete Grant 1074 | 1075 | \`DELETE /v3/applications/{application_id}/grants/{grant_id}\` 1076 | 1077 | Revokes a grant, disconnecting the user's account. 1078 | 1079 | **Parameters:** 1080 | - \`application_id\` (path): The ID of your application 1081 | - \`grant_id\` (path): The ID of the grant 1082 | 1083 | **Response:** 1084 | - \`status\`: Success status 1085 | 1086 | ### Update Grant 1087 | 1088 | \`PUT /v3/applications/{application_id}/grants/{grant_id}\` 1089 | 1090 | Updates properties of a grant. 1091 | 1092 | **Parameters:** 1093 | - \`application_id\` (path): The ID of your application 1094 | - \`grant_id\` (path): The ID of the grant 1095 | 1096 | **Request Body:** 1097 | - \`status\` (optional): New status ("active" or "disabled") 1098 | - \`ip_restrictions\` (optional): IP address restrictions 1099 | - \`scopes\` (optional): Updated permission scopes 1100 | 1101 | **Response:** 1102 | - Updated grant object` 1103 | }; 1104 | 1105 | // Return the content for the requested category, or a not found message 1106 | const content = categories[categoryStr] || `# Category Not Found\n\nThe requested endpoint category "${categoryStr}" is not available.`; 1107 | 1108 | return { 1109 | contents: [{ 1110 | uri: uri.href, 1111 | text: content, 1112 | mimeType: "text/markdown" 1113 | }] 1114 | }; 1115 | } 1116 | ); 1117 | } ``` -------------------------------------------------------------------------------- /src/tools/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 2 | import { z } from "zod"; 3 | 4 | /** 5 | * Register all tools with the MCP server 6 | */ 7 | export function registerTools(server: McpServer) { 8 | // Register code generation tools 9 | registerCodeGenerationTools(server); 10 | 11 | // Register API explorer tools 12 | registerApiExplorerTools(server); 13 | } 14 | 15 | /** 16 | * Register code generation tools 17 | */ 18 | function registerCodeGenerationTools(server: McpServer) { 19 | // Tool to generate authentication code for a specific language 20 | server.tool( 21 | "generate-auth-code", 22 | { 23 | language: z.enum(["node", "python", "java", "ruby", "curl"]), 24 | clientId: z.string().optional(), 25 | clientSecret: z.string().optional(), 26 | redirectUri: z.string().optional(), 27 | scopes: z.array(z.string()).optional() 28 | }, 29 | async ({ language, clientId, clientSecret, redirectUri, scopes }) => { 30 | const normalizedLanguage = normalizeLanguage(language); 31 | const placeholderClientId = clientId || "YOUR_CLIENT_ID"; 32 | const placeholderClientSecret = clientSecret || "YOUR_CLIENT_SECRET"; 33 | const placeholderRedirectUri = redirectUri || "YOUR_REDIRECT_URI"; 34 | const placeholderScopes = scopes || ["email", "calendar", "contacts"]; 35 | 36 | // Map of languages to their authentication code templates 37 | const templates: Record<string, string> = { 38 | "Node": ` 39 | // Authentication with Nylas API using Node.js 40 | import { Nylas } from '@nylas/nylas-js'; 41 | 42 | // Initialize Nylas client 43 | Nylas.config({ 44 | clientId: "${placeholderClientId}", 45 | clientSecret: "${placeholderClientSecret}", 46 | }); 47 | 48 | // Generate OAuth URL to redirect the user to 49 | const authUrl = Nylas.urlForAuthentication({ 50 | redirectURI: "${placeholderRedirectUri}", 51 | scopes: ${JSON.stringify(placeholderScopes)}, 52 | }); 53 | 54 | console.log("Redirect the user to:", authUrl); 55 | 56 | // After the user is redirected back to your redirect URI: 57 | // Exchange the authorization code for an access token 58 | async function exchangeCodeForToken(code) { 59 | try { 60 | const tokenData = await Nylas.exchangeCodeForToken(code); 61 | console.log("Access token:", tokenData.accessToken); 62 | console.log("Grant ID:", tokenData.grantId); 63 | 64 | // Now you can use this token to make API calls 65 | return tokenData; 66 | } catch (error) { 67 | console.error("Error exchanging code for token:", error); 68 | } 69 | } 70 | 71 | // Call this function with the code from the URL parameter 72 | // exchangeCodeForToken(codeFromUrl); 73 | `, 74 | 75 | "Python": ` 76 | # Authentication with Nylas API using Python 77 | from nylas import Client 78 | import os 79 | 80 | # Initialize Nylas client 81 | nylas = Client( 82 | client_id="${placeholderClientId}", 83 | client_secret="${placeholderClientSecret}" 84 | ) 85 | 86 | # Generate OAuth URL to redirect the user to 87 | auth_url = nylas.authentication_url( 88 | redirect_uri="${placeholderRedirectUri}", 89 | scopes=${placeholderScopes} 90 | ) 91 | 92 | print("Redirect the user to:", auth_url) 93 | 94 | # After the user is redirected back to your redirect URI: 95 | # Exchange the authorization code for an access token 96 | def exchange_code_for_token(code): 97 | try: 98 | token_data = nylas.exchange_code_for_token(code) 99 | print("Access token:", token_data['access_token']) 100 | print("Grant ID:", token_data['grant_id']) 101 | 102 | # Now you can use this token to make API calls 103 | return token_data 104 | except Exception as e: 105 | print("Error exchanging code for token:", e) 106 | 107 | # Call this function with the code from the URL parameter 108 | # exchange_code_for_token(code_from_url) 109 | `, 110 | 111 | "Java": ` 112 | // Authentication with Nylas API using Java 113 | import com.nylas.NylasClient; 114 | import com.nylas.models.*; 115 | 116 | public class NylasAuth { 117 | public static void main(String[] args) { 118 | // Initialize Nylas client 119 | NylasClient nylas = new NylasClient.Builder("${placeholderClientId}") 120 | .clientSecret("${placeholderClientSecret}") 121 | .build(); 122 | 123 | // Generate OAuth URL to redirect the user to 124 | String authUrl = nylas.auth().urlForAuthentication( 125 | "${placeholderRedirectUri}", 126 | ${placeholderScopes.map(scope => '"' + scope + '"').join(", ")} 127 | ); 128 | 129 | System.out.println("Redirect the user to: " + authUrl); 130 | 131 | // After the user is redirected back to your redirect URI: 132 | // Exchange the authorization code for an access token 133 | String code = "CODE_FROM_URL_PARAMETER"; 134 | 135 | try { 136 | TokenResponse tokenData = nylas.auth().exchangeCodeForToken(code); 137 | System.out.println("Access token: " + tokenData.getAccessToken()); 138 | System.out.println("Grant ID: " + tokenData.getGrantId()); 139 | 140 | // Now you can use this token to make API calls 141 | } catch (Exception e) { 142 | System.err.println("Error exchanging code for token: " + e.getMessage()); 143 | } 144 | } 145 | } 146 | `, 147 | 148 | "Ruby": ` 149 | # Authentication with Nylas API using Ruby 150 | require 'nylas' 151 | 152 | # Initialize Nylas client 153 | nylas = Nylas::Client.new( 154 | client_id: "${placeholderClientId}", 155 | client_secret: "${placeholderClientSecret}" 156 | ) 157 | 158 | # Generate OAuth URL to redirect the user to 159 | auth_url = nylas.auth.authorize_url( 160 | redirect_uri: "${placeholderRedirectUri}", 161 | scopes: ${JSON.stringify(placeholderScopes)} 162 | ) 163 | 164 | puts "Redirect the user to: #{auth_url}" 165 | 166 | # After the user is redirected back to your redirect URI: 167 | # Exchange the authorization code for an access token 168 | def exchange_code_for_token(code) 169 | begin 170 | token_data = nylas.auth.exchange_code_for_token(code) 171 | puts "Access token: #{token_data.access_token}" 172 | puts "Grant ID: #{token_data.grant_id}" 173 | 174 | # Now you can use this token to make API calls 175 | return token_data 176 | rescue => e 177 | puts "Error exchanging code for token: #{e.message}" 178 | end 179 | end 180 | 181 | # Call this function with the code from the URL parameter 182 | # exchange_code_for_token(code_from_url) 183 | `, 184 | 185 | "curl": ` 186 | # Authentication with Nylas API using curl 187 | 188 | # Step 1: Generate an authorization URL (typically done in your backend) 189 | # Users will be redirected to this URL to authorize your application 190 | 191 | # Step 2: After authorization, the user is redirected to your redirect URI with a code 192 | # For example: ${placeholderRedirectUri}?code=AUTHORIZATION_CODE 193 | 194 | # Step 3: Exchange the authorization code for an access token 195 | curl --request POST \\ 196 | --url "https://api.us.nylas.com/v3/connect/oauth/token" \\ 197 | --header "Content-Type: application/json" \\ 198 | --data '{ 199 | "client_id": "${placeholderClientId}", 200 | "client_secret": "${placeholderClientSecret}", 201 | "grant_type": "authorization_code", 202 | "code": "AUTHORIZATION_CODE_FROM_REDIRECT", 203 | "redirect_uri": "${placeholderRedirectUri}" 204 | }' 205 | 206 | # Response will contain access_token, refresh_token, grant_id, etc. 207 | 208 | # Step 4: Use the access token to make API calls 209 | curl --request GET \\ 210 | --url "https://api.us.nylas.com/v3/grants/GRANT_ID/messages?limit=10" \\ 211 | --header "Content-Type: application/json" \\ 212 | --header "Authorization: Bearer ACCESS_TOKEN" 213 | ` 214 | }; 215 | 216 | // Get the template for the requested language, or provide an error message 217 | const template = templates[normalizedLanguage] || 218 | `Code generation is not available for ${language}. Available languages are: Node.js, Python, Java, Ruby, and curl.`; 219 | 220 | return { 221 | content: [ 222 | { 223 | type: "text", 224 | text: template 225 | } 226 | ] 227 | }; 228 | } 229 | ); 230 | 231 | // Tool to generate code for a specific API endpoint 232 | server.tool( 233 | "generate-endpoint-code", 234 | { 235 | language: z.enum(["node", "python", "java", "ruby", "curl"]), 236 | endpoint: z.string(), 237 | method: z.enum(["GET", "POST", "PUT", "DELETE"]).optional(), 238 | params: z.record(z.any()).optional() 239 | }, 240 | async ({ language, endpoint, method = "GET", params = {} }) => { 241 | const normalizedLanguage = normalizeLanguage(language); 242 | const endpointPath = endpoint.startsWith("/") ? endpoint : `/${endpoint}`; 243 | 244 | // Construct the endpoint with path parameters 245 | let formattedEndpoint = endpointPath; 246 | 247 | // Replace path parameters with values from params 248 | Object.keys(params).forEach(key => { 249 | if (formattedEndpoint.includes(`{${key}}`)) { 250 | formattedEndpoint = formattedEndpoint.replace(`{${key}}`, params[key]); 251 | delete params[key]; // Remove used path parameters 252 | } 253 | }); 254 | 255 | // Map of languages to their API code templates 256 | const templates: Record<string, string> = { 257 | "Node": ` 258 | // ${method} ${endpointPath} using Nylas Node.js SDK 259 | import 'dotenv/config'; 260 | import Nylas from '@nylas/nylas-js'; 261 | 262 | // Initialize the Nylas client 263 | const nylas = new Nylas({ 264 | apiKey: process.env.NYLAS_API_KEY 265 | }); 266 | 267 | async function callNylasApi() { 268 | try { 269 | ${generateNodeCode(method, formattedEndpoint, params)} 270 | 271 | console.log(response); 272 | return response; 273 | } catch (error) { 274 | console.error('Error calling Nylas API:', error); 275 | } 276 | } 277 | 278 | callNylasApi(); 279 | `, 280 | 281 | "Python": ` 282 | # ${method} ${endpointPath} using Nylas Python SDK 283 | from dotenv import load_dotenv 284 | load_dotenv() 285 | 286 | import os 287 | from nylas import Client 288 | 289 | # Initialize the Nylas client 290 | nylas = Client( 291 | api_key=os.environ.get('NYLAS_API_KEY') 292 | ) 293 | 294 | ${generatePythonCode(method, formattedEndpoint, params)} 295 | 296 | print(response) 297 | `, 298 | 299 | "Java": ` 300 | // ${method} ${endpointPath} using Nylas Java SDK 301 | import com.nylas.NylasClient; 302 | import com.nylas.models.*; 303 | 304 | public class NylasApiExample { 305 | public static void main(String[] args) { 306 | try { 307 | // Initialize the Nylas client 308 | NylasClient nylas = new NylasClient.Builder(System.getenv("NYLAS_API_KEY")).build(); 309 | 310 | ${generateJavaCode(method, formattedEndpoint, params)} 311 | 312 | System.out.println(response); 313 | } catch (Exception e) { 314 | System.err.println("Error calling Nylas API: " + e.getMessage()); 315 | } 316 | } 317 | } 318 | `, 319 | 320 | "Ruby": ` 321 | # ${method} ${endpointPath} using Nylas Ruby SDK 322 | require 'nylas' 323 | require 'dotenv/load' 324 | 325 | # Initialize the Nylas client 326 | nylas = Nylas::Client.new( 327 | api_key: ENV['NYLAS_API_KEY'] 328 | ) 329 | 330 | ${generateRubyCode(method, formattedEndpoint, params)} 331 | 332 | puts response 333 | `, 334 | 335 | "curl": ` 336 | # ${method} ${endpointPath} using curl 337 | ${generateCurlCode(method, formattedEndpoint, params)} 338 | ` 339 | }; 340 | 341 | // Get the template for the requested language, or provide an error message 342 | const template = templates[normalizedLanguage] || 343 | `Code generation is not available for ${language}. Available languages are: Node.js, Python, Java, Ruby, and curl.`; 344 | 345 | return { 346 | content: [ 347 | { 348 | type: "text", 349 | text: template 350 | } 351 | ] 352 | }; 353 | } 354 | ); 355 | } 356 | 357 | /** 358 | * Register API explorer tools 359 | */ 360 | function registerApiExplorerTools(server: McpServer) { 361 | // Tool to search the Nylas API documentation 362 | server.tool( 363 | "search-api-docs", 364 | { 365 | query: z.string(), 366 | category: z.enum(["email", "calendar", "contacts", "auth", "webhooks"]).optional() 367 | }, 368 | async ({ query, category }) => { 369 | // Normalize the query for search 370 | const normalizedQuery = query.toLowerCase(); 371 | 372 | // Define search result templates 373 | const searchResults: Record<string, string[]> = { 374 | "email": [ 375 | `### Messages API 376 | The Messages API allows you to read, send, and search email messages. 377 | Key endpoints: 378 | - GET /v3/grants/{grant_id}/messages - List messages 379 | - GET /v3/grants/{grant_id}/messages/{message_id} - Get a specific message 380 | - POST /v3/grants/{grant_id}/messages - Send a message`, 381 | 382 | `### Threads API 383 | The Threads API allows you to manage email conversations. 384 | Key endpoints: 385 | - GET /v3/grants/{grant_id}/threads - List threads 386 | - GET /v3/grants/{grant_id}/threads/{thread_id} - Get a specific thread`, 387 | 388 | `### Drafts API 389 | The Drafts API allows you to create and manage email drafts. 390 | Key endpoints: 391 | - GET /v3/grants/{grant_id}/drafts - List drafts 392 | - POST /v3/grants/{grant_id}/drafts - Create a draft 393 | - POST /v3/grants/{grant_id}/drafts/{draft_id}/send - Send a draft` 394 | ], 395 | 396 | "calendar": [ 397 | `### Calendars API 398 | The Calendars API allows you to manage calendar containers. 399 | Key endpoints: 400 | - GET /v3/grants/{grant_id}/calendars - List calendars 401 | - GET /v3/grants/{grant_id}/calendars/{calendar_id} - Get a specific calendar`, 402 | 403 | `### Events API 404 | The Events API allows you to create and manage calendar events. 405 | Key endpoints: 406 | - GET /v3/grants/{grant_id}/events - List events 407 | - POST /v3/grants/{grant_id}/events - Create an event 408 | - PUT /v3/grants/{grant_id}/events/{event_id} - Update an event`, 409 | 410 | `### Availability API 411 | The Availability API helps find available time slots. 412 | Key endpoints: 413 | - POST /v3/grants/{grant_id}/calendars/availability - Find available time slots` 414 | ], 415 | 416 | "contacts": [ 417 | `### Contacts API 418 | The Contacts API allows you to manage contact information. 419 | Key endpoints: 420 | - GET /v3/grants/{grant_id}/contacts - List contacts 421 | - GET /v3/grants/{grant_id}/contacts/{contact_id} - Get a specific contact 422 | - POST /v3/grants/{grant_id}/contacts - Create a contact` 423 | ], 424 | 425 | "auth": [ 426 | `### Authentication API 427 | The Authentication API handles OAuth flows. 428 | Key endpoints: 429 | - GET /v3/connect/oauth/authorize - Start OAuth flow 430 | - POST /v3/connect/oauth/token - Exchange code for token or refresh token`, 431 | 432 | `### Grants API 433 | The Grants API manages connected accounts. 434 | Key endpoints: 435 | - GET /v3/applications/{application_id}/grants - List connected accounts 436 | - GET /v3/applications/{application_id}/grants/{grant_id} - Get a specific connected account` 437 | ], 438 | 439 | "webhooks": [ 440 | `### Webhooks API 441 | The Webhooks API allows setting up real-time notifications. 442 | Key endpoints: 443 | - GET /v3/applications/{application_id}/webhooks - List webhooks 444 | - POST /v3/applications/{application_id}/webhooks - Create a webhook 445 | - DELETE /v3/applications/{application_id}/webhooks/{webhook_id} - Delete a webhook` 446 | ] 447 | }; 448 | 449 | // If a category is specified, search only in that category 450 | if (category) { 451 | const categoryResults = searchResults[category] || []; 452 | const matches = categoryResults.filter(result => 453 | result.toLowerCase().includes(normalizedQuery) 454 | ); 455 | 456 | if (matches.length > 0) { 457 | return { 458 | content: [ 459 | { 460 | type: "text", 461 | text: `# Search results for "${query}" in ${category} API\n\n${matches.join('\n\n')}` 462 | } 463 | ] 464 | }; 465 | } else { 466 | return { 467 | content: [ 468 | { 469 | type: "text", 470 | text: `No results found for "${query}" in the ${category} API. Try a different search term or category.` 471 | } 472 | ] 473 | }; 474 | } 475 | } 476 | 477 | // If no category is specified, search in all categories 478 | const allResults: string[] = []; 479 | 480 | Object.entries(searchResults).forEach(([category, results]) => { 481 | const categoryMatches = results.filter(result => 482 | result.toLowerCase().includes(normalizedQuery) 483 | ); 484 | 485 | if (categoryMatches.length > 0) { 486 | allResults.push(`## ${category.charAt(0).toUpperCase() + category.slice(1)} API\n\n${categoryMatches.join('\n\n')}`); 487 | } 488 | }); 489 | 490 | if (allResults.length > 0) { 491 | return { 492 | content: [ 493 | { 494 | type: "text", 495 | text: `# Search results for "${query}"\n\n${allResults.join('\n\n')}` 496 | } 497 | ] 498 | }; 499 | } else { 500 | return { 501 | content: [ 502 | { 503 | type: "text", 504 | text: `No results found for "${query}". Try a different search term.` 505 | } 506 | ] 507 | }; 508 | } 509 | } 510 | ); 511 | } 512 | 513 | /** 514 | * Normalize language names for code generation 515 | */ 516 | function normalizeLanguage(language: string): string { 517 | const langMap: Record<string, string> = { 518 | 'node': 'Node', 519 | 'nodejs': 'Node', 520 | 'javascript': 'Node', 521 | 'js': 'Node', 522 | 'python': 'Python', 523 | 'py': 'Python', 524 | 'java': 'Java', 525 | 'ruby': 'Ruby', 526 | 'rb': 'Ruby', 527 | 'curl': 'curl', 528 | 'api': 'curl', 529 | 'rest': 'curl' 530 | }; 531 | 532 | return langMap[language.toLowerCase()] || language; 533 | } 534 | 535 | /** 536 | * Generate Node.js code for the API endpoint 537 | */ 538 | function generateNodeCode(method: string, endpoint: string, params: Record<string, any>): string { 539 | const parts = endpoint.split('/'); 540 | let resourceType = ''; 541 | let functionName = ''; 542 | let grantId = 'process.env.NYLAS_GRANT_ID'; 543 | let resourceId = ''; 544 | 545 | // Try to determine the resource type and function name 546 | if (parts.length >= 3) { 547 | if (parts[1] === 'v3' && parts[2] === 'grants') { 548 | if (parts.length >= 5) { 549 | resourceType = parts[4]; // like 'messages', 'events', etc. 550 | 551 | if (parts.length >= 6) { 552 | resourceId = parts[5]; 553 | 554 | if (parts.length >= 7 && parts[6] === 'send') { 555 | functionName = 'send'; 556 | } 557 | } 558 | } 559 | } 560 | } 561 | 562 | // Handle different HTTP methods 563 | switch (method) { 564 | case 'GET': 565 | if (resourceId) { 566 | // Get a specific resource 567 | return `const response = await nylas.${resourceType}.find({ 568 | identifier: ${grantId}, 569 | ${resourceType.slice(0, -1)}Id: "${resourceId}", 570 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 571 | });`; 572 | } else { 573 | // List resources 574 | return `const response = await nylas.${resourceType}.list({ 575 | identifier: ${grantId}, 576 | ${Object.keys(params).length > 0 ? `queryParams: { 577 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 578 | }` : ''} 579 | });`; 580 | } 581 | 582 | case 'POST': 583 | if (functionName === 'send') { 584 | // Send a draft 585 | return `const response = await nylas.${resourceType}.send({ 586 | identifier: ${grantId}, 587 | ${resourceType.slice(0, -1)}Id: "${resourceId}" 588 | });`; 589 | } else { 590 | // Create a resource 591 | return `const response = await nylas.${resourceType}.create({ 592 | identifier: ${grantId}, 593 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 594 | });`; 595 | } 596 | 597 | case 'PUT': 598 | // Update a resource 599 | return `const response = await nylas.${resourceType}.update({ 600 | identifier: ${grantId}, 601 | ${resourceType.slice(0, -1)}Id: "${resourceId}", 602 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 603 | });`; 604 | 605 | case 'DELETE': 606 | // Delete a resource 607 | return `const response = await nylas.${resourceType}.destroy({ 608 | identifier: ${grantId}, 609 | ${resourceType.slice(0, -1)}Id: "${resourceId}" 610 | });`; 611 | 612 | default: 613 | return `// No code generation available for this endpoint 614 | const response = "Please refer to the Nylas API documentation for this endpoint.";`; 615 | } 616 | } 617 | 618 | /** 619 | * Generate Python code for the API endpoint 620 | */ 621 | function generatePythonCode(method: string, endpoint: string, params: Record<string, any>): string { 622 | const parts = endpoint.split('/'); 623 | let resourceType = ''; 624 | let functionName = ''; 625 | let grantId = 'os.environ.get("NYLAS_GRANT_ID")'; 626 | let resourceId = ''; 627 | 628 | // Try to determine the resource type and function name 629 | if (parts.length >= 3) { 630 | if (parts[1] === 'v3' && parts[2] === 'grants') { 631 | if (parts.length >= 5) { 632 | resourceType = parts[4]; // like 'messages', 'events', etc. 633 | 634 | if (parts.length >= 6) { 635 | resourceId = parts[5]; 636 | 637 | if (parts.length >= 7 && parts[6] === 'send') { 638 | functionName = 'send'; 639 | } 640 | } 641 | } 642 | } 643 | } 644 | 645 | // Handle different HTTP methods 646 | switch (method) { 647 | case 'GET': 648 | if (resourceId) { 649 | // Get a specific resource 650 | return `# Get a specific ${resourceType.slice(0, -1)} 651 | response = nylas.${resourceType}.find( 652 | ${grantId}, 653 | "${resourceId}"${Object.keys(params).length > 0 ? `, 654 | query_params={ 655 | ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n ')} 656 | }` : ''} 657 | )`; 658 | } else { 659 | // List resources 660 | return `# List ${resourceType} 661 | response = nylas.${resourceType}.list( 662 | ${grantId}${Object.keys(params).length > 0 ? `, 663 | query_params={ 664 | ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n ')} 665 | }` : ''} 666 | )`; 667 | } 668 | 669 | case 'POST': 670 | if (functionName === 'send') { 671 | // Send a draft 672 | return `# Send a draft 673 | response = nylas.${resourceType}.send( 674 | ${grantId}, 675 | "${resourceId}" 676 | )`; 677 | } else { 678 | // Create a resource 679 | return `# Create a new ${resourceType.slice(0, -1)} 680 | response = nylas.${resourceType}.create( 681 | ${grantId}, 682 | { 683 | ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n ')} 684 | } 685 | )`; 686 | } 687 | 688 | case 'PUT': 689 | // Update a resource 690 | return `# Update a ${resourceType.slice(0, -1)} 691 | response = nylas.${resourceType}.update( 692 | ${grantId}, 693 | "${resourceId}", 694 | { 695 | ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n ')} 696 | } 697 | )`; 698 | 699 | case 'DELETE': 700 | // Delete a resource 701 | return `# Delete a ${resourceType.slice(0, -1)} 702 | response = nylas.${resourceType}.destroy( 703 | ${grantId}, 704 | "${resourceId}" 705 | )`; 706 | 707 | default: 708 | return `# No code generation available for this endpoint 709 | response = "Please refer to the Nylas API documentation for this endpoint."`; 710 | } 711 | } 712 | 713 | /** 714 | * Generate Java code for the API endpoint 715 | */ 716 | function generateJavaCode(method: string, endpoint: string, params: Record<string, any>): string { 717 | const parts = endpoint.split('/'); 718 | let resourceType = ''; 719 | let functionName = ''; 720 | let grantId = 'System.getenv("NYLAS_GRANT_ID")'; 721 | let resourceId = ''; 722 | 723 | // Try to determine the resource type and function name 724 | if (parts.length >= 3) { 725 | if (parts[1] === 'v3' && parts[2] === 'grants') { 726 | if (parts.length >= 5) { 727 | resourceType = parts[4]; // like 'messages', 'events', etc. 728 | resourceType = resourceType.charAt(0).toUpperCase() + resourceType.slice(1); 729 | 730 | if (parts.length >= 6) { 731 | resourceId = parts[5]; 732 | 733 | if (parts.length >= 7 && parts[6] === 'send') { 734 | functionName = 'send'; 735 | } 736 | } 737 | } 738 | } 739 | } 740 | 741 | // Handle different HTTP methods 742 | switch (method) { 743 | case 'GET': 744 | if (resourceId) { 745 | // Get a specific resource 746 | return `// Get a specific ${resourceType.toLowerCase().slice(0, -1)} 747 | Response<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().find(${grantId}, "${resourceId}");`; 748 | } else { 749 | // List resources 750 | if (Object.keys(params).length > 0) { 751 | return `// List ${resourceType.toLowerCase()} with query parameters 752 | QueryParams queryParams = new QueryParams(); 753 | ${Object.entries(params).map(([key, value]) => `queryParams.put("${key}", ${JSON.stringify(value)});`).join('\n')} 754 | 755 | ListResponse<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().list(${grantId}, queryParams);`; 756 | } else { 757 | return `// List ${resourceType.toLowerCase()} 758 | ListResponse<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().list(${grantId});`; 759 | } 760 | } 761 | 762 | case 'POST': 763 | if (functionName === 'send') { 764 | // Send a draft 765 | return `// Send a draft 766 | Response<Message> response = nylas.${resourceType.toLowerCase()}().send(${grantId}, "${resourceId}");`; 767 | } else { 768 | // Create a resource 769 | return `// Create a new ${resourceType.toLowerCase().slice(0, -1)} 770 | ${resourceType.slice(0, -1)} new${resourceType.slice(0, -1)} = new ${resourceType.slice(0, -1)}.Builder() 771 | ${Object.entries(params).map(([key, value]) => { 772 | // Convert camelCase to method name (e.g., startTime -> startTime()) 773 | const methodName = key.charAt(0).toLowerCase() + key.slice(1); 774 | return ` .${methodName}(${JSON.stringify(value)})`; 775 | }).join('\n')} 776 | .build(); 777 | 778 | Response<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().create(${grantId}, new${resourceType.slice(0, -1)});`; 779 | } 780 | 781 | case 'PUT': 782 | // Update a resource 783 | return `// Update a ${resourceType.toLowerCase().slice(0, -1)} 784 | ${resourceType.slice(0, -1)} updated${resourceType.slice(0, -1)} = new ${resourceType.slice(0, -1)}.Builder() 785 | ${Object.entries(params).map(([key, value]) => { 786 | // Convert camelCase to method name (e.g., startTime -> startTime()) 787 | const methodName = key.charAt(0).toLowerCase() + key.slice(1); 788 | return ` .${methodName}(${JSON.stringify(value)})`; 789 | }).join('\n')} 790 | .build(); 791 | 792 | Response<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().update(${grantId}, "${resourceId}", updated${resourceType.slice(0, -1)});`; 793 | 794 | case 'DELETE': 795 | // Delete a resource 796 | return `// Delete a ${resourceType.toLowerCase().slice(0, -1)} 797 | Response<Void> response = nylas.${resourceType.toLowerCase()}().destroy(${grantId}, "${resourceId}");`; 798 | 799 | default: 800 | return `// No code generation available for this endpoint 801 | String response = "Please refer to the Nylas API documentation for this endpoint.";`; 802 | } 803 | } 804 | 805 | /** 806 | * Generate Ruby code for the API endpoint 807 | */ 808 | function generateRubyCode(method: string, endpoint: string, params: Record<string, any>): string { 809 | const parts = endpoint.split('/'); 810 | let resourceType = ''; 811 | let functionName = ''; 812 | let grantId = 'ENV["NYLAS_GRANT_ID"]'; 813 | let resourceId = ''; 814 | 815 | // Try to determine the resource type and function name 816 | if (parts.length >= 3) { 817 | if (parts[1] === 'v3' && parts[2] === 'grants') { 818 | if (parts.length >= 5) { 819 | resourceType = parts[4]; // like 'messages', 'events', etc. 820 | 821 | if (parts.length >= 6) { 822 | resourceId = parts[5]; 823 | 824 | if (parts.length >= 7 && parts[6] === 'send') { 825 | functionName = 'send'; 826 | } 827 | } 828 | } 829 | } 830 | } 831 | 832 | // Handle different HTTP methods 833 | switch (method) { 834 | case 'GET': 835 | if (resourceId) { 836 | // Get a specific resource 837 | return `# Get a specific ${resourceType.slice(0, -1)} 838 | response, _ = nylas.${resourceType}.find( 839 | identifier: ${grantId}, 840 | ${resourceType.slice(0, -1)}_id: "${resourceId}"${Object.keys(params).length > 0 ? `, 841 | query_params: { 842 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 843 | }` : ''} 844 | )`; 845 | } else { 846 | // List resources 847 | return `# List ${resourceType} 848 | response, _ = nylas.${resourceType}.list( 849 | identifier: ${grantId}${Object.keys(params).length > 0 ? `, 850 | query_params: { 851 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 852 | }` : ''} 853 | )`; 854 | } 855 | 856 | case 'POST': 857 | if (functionName === 'send') { 858 | // Send a draft 859 | return `# Send a draft 860 | response, _ = nylas.${resourceType}.send( 861 | identifier: ${grantId}, 862 | ${resourceType.slice(0, -1)}_id: "${resourceId}" 863 | )`; 864 | } else { 865 | // Create a resource 866 | return `# Create a new ${resourceType.slice(0, -1)} 867 | response, _ = nylas.${resourceType}.create( 868 | identifier: ${grantId}, 869 | request_body: { 870 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 871 | } 872 | )`; 873 | } 874 | 875 | case 'PUT': 876 | // Update a resource 877 | return `# Update a ${resourceType.slice(0, -1)} 878 | response, _ = nylas.${resourceType}.update( 879 | identifier: ${grantId}, 880 | ${resourceType.slice(0, -1)}_id: "${resourceId}", 881 | request_body: { 882 | ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n ')} 883 | } 884 | )`; 885 | 886 | case 'DELETE': 887 | // Delete a resource 888 | return `# Delete a ${resourceType.slice(0, -1)} 889 | response, _ = nylas.${resourceType}.destroy( 890 | identifier: ${grantId}, 891 | ${resourceType.slice(0, -1)}_id: "${resourceId}" 892 | )`; 893 | 894 | default: 895 | return `# No code generation available for this endpoint 896 | response = "Please refer to the Nylas API documentation for this endpoint."`; 897 | } 898 | } 899 | 900 | /** 901 | * Generate curl command for the API endpoint 902 | */ 903 | function generateCurlCode(method: string, endpoint: string, params: Record<string, any>): string { 904 | let baseUrl = "https://api.us.nylas.com"; 905 | const fullUrl = `${baseUrl}${endpoint}`; 906 | 907 | // Handle different HTTP methods 908 | switch (method) { 909 | case 'GET': 910 | // Add query parameters if any 911 | if (Object.keys(params).length > 0) { 912 | const queryParams = Object.entries(params) 913 | .map(([key, value]) => `${key}=${encodeURIComponent(JSON.stringify(value))}`) 914 | .join('&'); 915 | 916 | return `curl --request GET \\ 917 | --url "${fullUrl}?${queryParams}" \\ 918 | --header "Content-Type: application/json" \\ 919 | --header "Authorization: Bearer $NYLAS_API_KEY"`; 920 | } else { 921 | return `curl --request GET \\ 922 | --url "${fullUrl}" \\ 923 | --header "Content-Type: application/json" \\ 924 | --header "Authorization: Bearer $NYLAS_API_KEY"`; 925 | } 926 | 927 | case 'POST': 928 | // Include request body 929 | return `curl --request POST \\ 930 | --url "${fullUrl}" \\ 931 | --header "Content-Type: application/json" \\ 932 | --header "Authorization: Bearer $NYLAS_API_KEY" \\ 933 | --data '${JSON.stringify(params, null, 2)}'`; 934 | 935 | case 'PUT': 936 | // Include request body 937 | return `curl --request PUT \\ 938 | --url "${fullUrl}" \\ 939 | --header "Content-Type: application/json" \\ 940 | --header "Authorization: Bearer $NYLAS_API_KEY" \\ 941 | --data '${JSON.stringify(params, null, 2)}'`; 942 | 943 | case 'DELETE': 944 | return `curl --request DELETE \\ 945 | --url "${fullUrl}" \\ 946 | --header "Content-Type: application/json" \\ 947 | --header "Authorization: Bearer $NYLAS_API_KEY"`; 948 | 949 | default: 950 | return `# No code generation available for this endpoint 951 | # Please refer to the Nylas API documentation`; 952 | } 953 | } ```