#
tokens: 39678/50000 9/85 files (page 2/2)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 2. Use http://codebase.md/nylas-samples/nylas-api-mcp?lines=false&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

--------------------------------------------------------------------------------
/nylas-code-samples/Email/Messages/write.md:
--------------------------------------------------------------------------------

```markdown
### Update a specific message

`PUT /messages/<MESSAGE_ID>` → `PUT /v3/grants/<NYLAS_GRANT_ID>/messages/<MESSAGE_ID>`

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const identifier = process.env.NYLAS_GRANT_ID
const folderId = process.env.FOLDER_ID
const messageId = process.env.MESSAGE_ID

const updateMessageFolder = async () => {
  try {
    const updatedMessage = await nylas.messages.update({
      identifier,
      messageId,
      requestBody: {
          folders: [folderId]
      }
    })

    console.log('Message updated:', updatedMessage)
  } catch (error) {
    console.error('Error updating message folder:', error)
  }
}

updateMessageFolder()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;
import java.util.List;

public class UpdateMessage {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    UpdateMessageRequest request = new UpdateMessageRequest.Builder().
        unread(true).
        starred(true).
        build();

    Response<Message> message = nylas.messages().
        update(dotenv.get("NYLAS_GRANT_ID"), "<MESSAGE_ID>", request);

    System.out.println(message);
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
folder_id = os.environ.get("FOLDER_ID")
message_id = os.environ.get("MESSAGE_ID")

message = nylas.messages.update(
    grant_id,
    message_id,
    request_body={
      "folders": [folder_id]
    }
)

print(message)
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
    api_key: "<NYLAS_API_KEY>"
)

request_body = {
  unread: true,
  starred: true
}

message, _ = nylas.messages.update(identifier: "<NYLAS_GRANT_ID>",
    message_id: "<MESSAGE_ID>",
    request_body: request_body)

puts message
```

```API
curl --location --request PUT 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/<MESSAGE_ID>' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --data '{
    "folders": [
      "<FOLDER_ID>"
    ]
  }'
```

### Send a message

`POST /send` → `POST /v3/grants/<NYLAS_GRANT_ID>/messages/send`

```Node
app.get("/nylas/send-email", async (req, res) => {
  try {
    const sentMessage = await nylas.messages.send({
      identifier: process.env.USER_GRANT_ID,
      requestBody: {
        to: [{ name: "Name", email: process.env.EMAIL }],
        replyTo: [{ name: "Name", email: process.env.EMAIL }],
        subject: "Your Subject Here",
        body: "Your email body here.",
      },
    });

    res.json(sentMessage);
  } catch (error) {
    console.error("Error sending email:", error);
  }
});
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;
import java.util.ArrayList;
import java.util.List;

public class SendEmails {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    List<EmailName> emailNames = new ArrayList<>();
    emailNames.add(new EmailName("[email protected]", "John Doe"));

    TrackingOptions options = new TrackingOptions("hey just testing", true, true, true);

    SendMessageRequest requestBody = new SendMessageRequest.Builder(emailNames).
        trackingOptions(options).
        subject("Hey Reaching Out with Nylas").
        body("Hey I would like to track this link <a href='https://espn.com'>My Example Link</a>.").
        build();

    Response<Message> email = nylas.messages().send("<NYLAS_GRANT_ID>", requestBody);

    System.out.println(email.getData());
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
email = os.environ.get("EMAIL")

message = nylas.messages.send(
    grant_id,
    request_body={
      "to": [{ "name": "Name", "email": email }],
      "reply_to": [{ "name": "Name", "email": email }],
      "subject": "Your Subject Here",
      "body": "Your email body here.",
    }
)

print(message)
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
    api_key: "<NYLAS_API_KEY>"
)

request_body = {
  subject: "Hey Reaching Out with Nylas",
  body: "Hey I would like to track this link <a href='https://espn.com'>My Example Link</a>",
  to: [{name: "John Doe", email: "[email protected]"}],
  tracking_options: {label: "hey just testing",
    opens: true,
    links: true,
    thread_replies: true}
}

email, _ = nylas.messages.send(identifier: "<NYLAS_GRANT_ID>", request_body: request_body)

puts "Message \"#{email[:subject]}\" was sent with ID #{email[:id]}"
```

```API
curl --request POST \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "subject": "Hey Reaching Out with Nylas",
    "body": "Hey I would like to track this link <a href='https://espn.com'>My Example Link</a>",
    "to": [
      {
      "name": "John Doe",
      "email": "[email protected]"
      }
    ],
    "tracking_options": {
      "opens": true,
      "links": true,
      "thread_replies": true,
      "label": "hey just testing"
    }
  }'
```

### Delete a specific message

`DELETE /messages/<MESSAGE_ID>` → `DELETE /v3/grants/<NYLAS_GRANT_ID>/messages/<MESSAGE_ID>`

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

async function deleteMessage() { 
  try {
    const result = await nylas.messages.destroy({
      identifier: process.env.NYLAS_GRANT_ID,
      messageId: process.env.MESSAGE_ID,
    })
  
    console.log('Result:', result)
  } catch (error) {
    console.error('Error deleting message:', error)
  }
}

deleteMessage()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class ReturnMessage {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    DeleteResponse message = nylas.messages().destroy("<NYLAS_GRANT_ID>", "<MESSAGE_ID>");

    System.out.println(message);
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
message_id = os.environ.get("MESSAGE_ID")

result = nylas.messages.destroy(
    grant_id,
    message_id,
)

print(result)
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(
    api_key: "<NYLAS_API_KEY>"
)

status, _ = nylas.messages.destroy(identifier: "<NYLAS_GRANT_ID>", message_id: "<MESSAGE_ID>")

puts status
```

```API
curl --request DELETE \
  --url https://api.nylas.com/messages/<MESSAGE_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_ACCESS_TOKEN>' \
  --header 'Content-Type: application/json'
```

### Compose a message using AI

You can use the [`POST /v3/grants/<NYLAS_GRANT_ID>/messages/smart-compose` endpoint](https://developer.nylas.com/docs/api/v3/ecc/#post-/v3/grants/-grant_id-/messages/smart-compose) to generate an email message based on a text prompt.

```API
curl --request POST \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/smart-compose' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json'
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

async function composeEmail() {
  try {
    const message = await nylas.messages.smartCompose.composeMessage({
        identifier: process.env.NYLAS_GRANT_ID,
        requestBody: {
          prompt: 'Tell my colleague how we can use Nylas APIs',
        }
    })
    
    console.log('Message created:', message)
  } catch (error) {
    console.error('Error creating message:', error)
  }
}

composeEmail()
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(
   api_key: "<NYLAS_API_KEY>"
)

request_body = {
  prompt: 'Let''s talk about Nylas'
}

message, _ = nylasnylas.messages.smart_compose.compose_message(identifier: "<NYLAS_GRANT_ID>", 
    request_body: request_body)

puts message[:suggestion]
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
email = os.environ.get("EMAIL")

message = nylas.messages.smart_compose.compose_message(
    grant_id,
    request_body={
      "prompt": "Tell my colleague how we can use Nylas APIs",
    }
)

print(message)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class SmartCompose {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    ComposeMessageRequest requestBody = new ComposeMessageRequest("Let's talk about Nylas");
    Response<ComposeMessageResponse> message = nylas.messages().smartCompose().composeMessage("<NYLAS_GRANT_ID>", requestBody);
    
    System.out.println(message.getData().getSuggestion());
  }
}
```

### Compose a reply to a specific message using AI

You can use the [`POST /v3/grants/<NYLAS_GRANT_ID>/messages/<MESSAGE_ID>/smart-compose` endpoint](https://developer.nylas.com/docs/api/v3/ecc/#post-/v3/grants/-grant_id-/messages/-message_id-/smart-compose) to generate a reply to a specific email message.

```

--------------------------------------------------------------------------------
/nylas-code-samples/Email/Drafts/write.md:
--------------------------------------------------------------------------------

```markdown
### Update a specific draft

`PUT /drafts/<DRAFT_ID>` → [`PUT /v3/grants/<NYLAS_GRANT_ID>/drafts/<DRAFT_ID>`](https://developer.nylas.com/docs/api/v3/ecc/#put-/v3/grants/-grant_id-/drafts/-draft_id-)

```API
curl --request PUT \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/drafts/<DRAFT_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "unread": true,
    "starred": true
  }'
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

async function updateDraft() {
  try {
    const calendar = await nylas.drafts.update({
      identifier: process.env.NYLAS_GRANT_ID,
      draftId: process.env.DRAFT_ID,
      requestBody: {
        starred: true
      }
    })

    console.log('Updated Draft:', calendar)
  } catch (error) {
    console.error('Error to update draft:', error)
  }
}

updateDraft()
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
    api_key: "<NYLAS_API_KEY>"
)

request_body = {
  unread: true,
  starred: true
}

draft, _ = nylas.drafts.update(identifier: "<NYLAS_GRANT_ID>",
    draft_id: "<DRAFT_ID>",
    request_body: request_body)

puts draft
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")

thread = nylas.drafts.update(
    grant_id,
    draft_id=os.environ.get("DRAFT_ID"),
    request_body={
      "scope": ["mail.ready"]
    }
)

print(thread)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class UpdateDraft {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    UpdateDraftRequest requestBody = new UpdateDraftRequest.
        Builder().
        unread(true).
        starred(true).
        build();

    Response<Draft> draft = nylas.drafts().update("<NYLAS_GRANT_ID>", "<DRAFT_ID>", requestBody);

    System.out.printf("%s%s%s%n",
        draft.getData().getId(),
        draft.getData().getUnread(),
        draft.getData().getStarred());
  }
}
```

### Create a draft

`POST /drafts` → [`POST /v3/grants/<NYLAS_GRANT_ID>/drafts`](https://developer.nylas.com/docs/api/v3/ecc/#post-/v3/grants/-grant_id-/drafts)

```API
curl --request POST \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/drafts \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "subject": "With Love, From Nylas",
    "to": [{
      "email": "[email protected]",
      "name": "Dorothy Vaughan"
    }],
    "cc": [{
      "email": "George Washington Carver",
      "name": "[email protected]"
    }],
    "bcc": [{
      "email": "Albert Einstein",
      "name": "[email protected]"
    }],
    "reply_to": [{
      "email": "[email protected]",
      "name": "Stephanie Kwolek"
    }],
    "body": "This email was sent using the Nylas Email API. Visit https://nylas.com for details.",
    "tracking_options": {
      "opens": true,
      "links": true,
      "thread_replies": true,
      "label": "just testing"
    }
  }'
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const identifier = process.env.NYLAS_GRANT_ID

const createDraft = async () => {
  try {
    const draft = {
      subject: "With Love, From Nylas",
      to: [{ name: "Dorothy Vaughan", email: "[email protected]" }],
      body: "This email was sent using the Nylas Email API. Visit https://nylas.com for details.",
    }

    const createdDraft = await nylas.drafts.create({
        identifier,
        requestBody: draft
    })

    console.log('Draft created:', createdDraft)

  } catch (error) {
    console.error('Error creating draft:', error)
  }
}

createDraft()
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
    api_key: "<NYLAS_API_KEY>"
)

request_body = {
  subject: "With Love, From Nylas",
  body: 'This email was sent using the Nylas Email API. ' + 
      'Visit https://nylas.com for details.',
  to: [{
    name: "Dorothy Vaughan", 
    email: "[email protected]"
  }],
  cc: [{
    name: "George Washington Carver", 
    email: "[email protected]"
  }],
  bcc: [{
    name: "Albert Einstein", 
    email: "[email protected]"
  }],
  reply_to: [{
    name: "Stephanie Kwolek", 
    email: "[email protected]"
  }],
  tracking_options: {
    label: "just testing", 
    opens: true, 
    links: true,
    thread_replies: true
  }
}

draft, _ = nylas.drafts.create(identifier: "<NYLAS_GRANT_ID>", request_body: request_body)

puts "Draft \"#{draft[:subject]}\" was created with ID: #{draft[:id]}"
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
email = os.environ.get("EMAIL")

draft = nylas.drafts.create(
    grant_id,
    request_body={
      "to": [{ "name": "Dorothy Vaughan", "email": email }],
      "reply_to": [{ "name": "Dorothy Vaughan", "email": email }],
      "subject": "With Love, From Nylas",
      "body": "This email was sent using the Nylas Email API. Visit https://nylas.com for details.",
    }
)

print(draft)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

import com.nylas.util.FileUtils;
import io.github.cdimascio.dotenv.Dotenv;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CreateDraft {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    CreateDraftRequest requestBody = new CreateDraftRequest.Builder().
        to(Collections.singletonList(new EmailName("[email protected]", "Dorothy Vaughan"))).
        cc(Collections.singletonList(new EmailName("[email protected]", "George Washington Carver"))).
        bcc(Collections.singletonList(new EmailName("[email protected]", "Albert Einstein"))).
        subject("With Love, From Nylas").
        body("This email was sent using the Nylas Email API. Visit https://nylas.com for details.").
        build();

    Response<Draft> drafts = nylas.drafts().create(dotenv.get("NYLAS_GRANT_ID"), requestBody);

    System.out.println("Draft " + drafts.getData().getSubject() + 
        " was created with ID " + drafts.getData().getId());
  }
}
```

### Send a specific draft

You can use the [`POST /v3/grants/<NYLAS_GRANT_ID>/drafts/<DRAFT_ID>` endpoint](https://developer.nylas.com/docs/api/v3/ecc/#post-/v3/grants/-grant_id-/drafts/-draft_id-) to send a draft.

```API
curl --request POST \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/drafts/<DRAFT_ID>  \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const identifier = process.env.NYLAS_GRANT_ID
const draftId = process.env.DRAFT_ID

const sendDraft = async () => {
  try {
    const sentMessage = await nylas.drafts.send({ identifier, draftId })

    console.log('Draft sent:', sentMessage)
  } catch (error) {
    console.error('Error sending draft:', error)
  }
}

sendDraft()
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(
    api_key: "<NYLAS_API_KEY>"
)

draft, _ = nylas.drafts.send(identifier: "<NYLAS_GRANT_ID>", draft_id: "<DRAFT_ID>")
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
draft_id = os.environ.get("DRAFT_ID")

draft = nylas.drafts.send(
    grant_id,
    draft_id
)

print(draft)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class SendDraft {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    Response<Message> draft = nylas.drafts().send("<NYLAS_GRANT_ID>", "<DRAFT_ID>");

    System.out.println(draft.getData());
  }
}
```

### Delete a specific draft

`DELETE /drafts/<DRAFT_ID>` → [`DELETE /v3/grants/<NYLAS_GRANT_ID>/drafts/<DRAFT_ID>`](https://developer.nylas.com/docs/api/v3/ecc/#delete-/v3/grants/-grant_id-/drafts/-draft_id-)

```API
curl --request DELETE \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/drafts/<DRAFT_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json'
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const identifier = process.env.NYLAS_GRANT_ID
const draftId = process.env.DRAFT_ID

const deleteDraft = async () => {
  try {
    await nylas.drafts.destroy({ identifier, draftId })

    console.log(\`Draft with ID \${draftId} deleted successfully.\`)
  } catch (error) {
    console.error(\`Error deleting contact with ID \${draftId}:\`, error)
  }
}

deleteDraft()
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
   api_key: "<NYLAS_API_KEY>"
)

status, _ =  nylas.drafts.destroy(identifier: "<NYLAS_GRANT_ID>", draft_id: "<DRAFT_ID>")

if status
  puts "Draft successfully deleted"
end
```

```Python
from nylas import Client

nylas = Client(
    api_key = "<NYLAS_API_KEY>"
)

drafts = nylas.drafts.destroy("<NYLAS_GRANT_ID>", "<DRAFT_ID>")

print(drafts)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class SendDraft {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    DeleteResponse draft = nylas.drafts().destroy("<NYLAS_GRANT_ID>", "<DRAFT_ID>");

    System.out.println(draft.getRequestId());
  }
}
```

```

--------------------------------------------------------------------------------
/nylas-code-samples/Contacts/write.md:
--------------------------------------------------------------------------------

```markdown
### Update a specific contact

`PUT /contacts/<CONTACT_ID>` → [`PUT /v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>`](https://developer.nylas.com/docs/api/v3/ecc/#put-/v3/grants/-grant_id-/contacts/-contact_id-)

```API
curl --request PUT \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "birthday": "1960-12-31",
    "company_name": "Nylas",
    "emails": [
      {
        "email": "[email protected]",
        "type": "work"
      },
      {
        "email": "[email protected]",
        "type": "home"
      }
    ],
    "given_name": "John",
    "groups": [
      {
        "id": "starred"
      },
      {
        "id": "all"
      }
    ],
    "im_addresses": [
      {
        "type": "jabber",
        "im_address": "myjabberaddress"
      },
      {
        "type": "msn",
        "im_address": "mymsnaddress"
      }
    ],
    "job_title": "Software Engineer",
    "manager_name": "Bill",
    "middle_name": "Jacob",
    "nickname": "JD",
    "notes": "Loves Ramen",
    "office_location": "123 Main Street",
    "phone_numbers": [
      {
        "number": "+1-555-555-5555",
        "type": "work"
      },
      {
        "number": "+1-555-555-5556",
        "type": "home"
      }
    ],
    "physical_addresses": [
      {
        "type": "work",
        "street_address": "123 Main Street",
        "postal_code": 94107,
        "state": "CA",
        "country": "USA",
        "city": "San Francisco"
      },
      {
        "type": "home",
        "street_address": "456 Main Street",
        "postal_code": 94107,
        "state": "CA",
        "country": "USA",
        "city": "San Francisco"
      }
    ],
    "suffix": "Jr.",
    "surname": "Doe",
    "web_pages": [
      {
        "type": "work",
        "url": "http://www.linkedin.com/in/johndoe"
      },
      {
        "type": "home",
        "url": "http://www.johndoe.com"
      }
    ]
  }'
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

async function updateContact() {
  try {
    const contact = await nylas.contacts.update({
      identifier: process.env.NYLAS_GRANT_ID,
      contactId: process.env.CONTACT_ID,
      requestBody: {
        givenName: "Nyla",
      }
    })

    console.log('Contact:', JSON.stringify(contact))
  } catch (error) {
    console.error('Error to create contact:', error)
  }
}

updateContact()
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

request_body = {
  notes: "This is *the best* swag",
}

contact, _ = nylas.contacts.update(identifier: "<NYLAS_GRANT_ID>", 
    contact_id: "<CONTACT_ID>", 
    request_body: request_body)

puts contact
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
contact_id = os.environ.get("CONTACT_ID")

contact = nylas.contacts.update(
    grant_id,
    contact_id,
    request_body={
      "given_name": "Nyla",
    }
)

print(contact)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class UpdateContact {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    UpdateContactRequest requestBody = new UpdateContactRequest.
        Builder().
        notes("This is *the best* swag").
        build();

    Response<Contact> contact = nylas.contacts().update("<NYLAS_GRANT_ID>", "<CONTACT_ID>", requestBody);

    System.out.println(contact);
  }
}
```

### Create a contact

`POST /contacts` → [`POST /v3/grants/<NYLAS_GRANT_ID>/contacts`](https://developer.nylas.com/docs/api/v3/ecc/#post-/v3/grants/-grant_id-/contacts)

```API
curl --request POST \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "birthday": "1960-12-31",
    "company_name": "Nylas",
    "emails": [
      {
        "email": "[email protected]",
        "type": "work"
      },
      {
        "email": "[email protected]",
        "type": "home"
      }
    ],
    "given_name": "John",
    "groups": [
      {
        "id": "starred"
      },
      {
        "id": "all"
      }
    ],
    "im_addresses": [
      {
        "type": "jabber",
        "im_address": "myjabberaddress"
      },
      {
        "type": "msn",
        "im_address": "mymsnaddress"
      }
    ],
    "job_title": "Software Engineer",
    "manager_name": "Bill",
    "middle_name": "Jacob",
    "nickname": "JD",
    "notes": "Loves ramen",
    "office_location": "123 Main Street",
    "phone_numbers": [
      {
        "number": "+1-555-555-5555",
        "type": "work"
      },
      {
        "number": "+1-555-555-5556",
        "type": "home"
      }
    ],
    "physical_addresses": [
      {
        "type": "work",
        "street_address": "123 Main Street",
        "postal_code": 94107,
        "state": "CA",
        "country": "USA",
        "city": "San Francisco"
      },
      {
        "type": "home",
        "street_address": "456 Main Street",
        "postal_code": 94107,
        "state": "CA",
        "country": "USA",
        "city": "San Francisco"
      }
    ],
    "suffix": "Jr.",
    "surname": "Doe",
    "web_pages": [
      {
        "type": "work",
        "url": "http://www.linkedin.com/in/johndoe"
      },
      {
        "type": "home",
        "url": "http://www.johndoe.com"
      }
    ]
  }'
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

async function createContact() {
  try {
    const contact = await nylas.contacts.create({
      identifier: process.env.NYLAS_GRANT_ID,
      requestBody: {
        givenName: "My",
        middleName: "Nylas",
        surname: "Friend",
        notes: "Make sure to keep in touch!",
        emails: [{type: 'work', email: '[email protected]'}],
        phoneNumbers: [{type: 'work', number: '(555) 555-5555'}],
        webPages: [{type: 'other', url: 'nylas.com'}]
      }
    })

    console.log('Contact:', JSON.stringify(contact))
  } catch (error) {
    console.error('Error to create contact:', error)
  }
}

createContact()
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

request_body = {
  given_name: "My",
  middle_name: "Nylas",
  surname: "Friend",  
  emails: [{email: "[email protected]", type: "work"}],
  notes: "Make sure to keep in touch!",
  phone_numbers: [{number: "555 555-5555", type: "business"}],
  web_pages: [{url: "https://www.nylas.com", type: "homepage"}]
}

contact, _ = nylas.contacts.create(identifier: "<NYLAS_GRANT_ID>", request_body: request_body)

puts contact
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")

contact = nylas.contacts.create(
    grant_id,
    request_body={
      "middleName": "Nylas",
      "surname": "Friend",
      "notes": "Make sure to keep in touch!",
      "emails": [{"type": "work", "email": "[email protected]"}],
      "phoneNumbers": [{"type": "work", "number": "(555) 555-5555"}],
      "webPages": [{"type": "other", "url": "nylas.com"}]
    }
)

print(contact)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;
import java.util.ArrayList;
import java.util.List;

public class CreateAContact {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    List<ContactEmail> contactEmails = new ArrayList<>();
    contactEmails.add(new ContactEmail("[email protected]", "work"));

    List<WebPage> contactWebpages = new ArrayList<>();
    contactWebpages.add(new WebPage("https://www.nylas.com", "work"));

    CreateContactRequest requestBody = new CreateContactRequest.Builder().
        emails(contactEmails).
        companyName("Nylas").
        givenName("Nylas' Swag").
        notes("This is good swag").
        webPages(contactWebpages).
        build();

    Response<Contact> contact = nylas.contacts().create("<NYLAS_GRANT_ID>", requestBody);

    System.out.println(contact);
  }
}
```

### Delete a specific contact

`DELETE /contacts/<CONTACT_ID>` → [`DELETE /v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>](https://developer.nylas.com/docs/api/v3/ecc/#delete-/v3/grants/-grant_id-/contacts/-contact_id-)

```API
curl --request DELETE \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json'
```

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const identifier = process.env.NYLAS_GRANT_ID
const contactId = process.env.CONTACT_ID

const deleteContact = async () => {
  try {
    await nylas.contacts.destroy({ identifier, contactId })
    console.log(`Contact with ID ${contactId} deleted successfully.`)
  } catch (error) {
    console.error(`Error deleting contact with ID ${contactId}:`, error)
  }
}

deleteContact()
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")
status, _ = nylas.contacts.destroy(identifier: "<NYLAS_GRANT_ID>", contact_id: "<CONTACT_ID>")

puts status
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
contact_id = os.environ.get("CONTACT_ID")

request = nylas.contacts.destroy(
    grant_id,
    contact_id,
)

print(request)
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class DeleteAContact {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    DeleteResponse contact = nylas.contacts().destroy("<NYLAS_GRANT_ID>", "<CONTACT_ID>");

    System.out.println(contact);
  }
}
```

```

--------------------------------------------------------------------------------
/src/resources/docs.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";

/**
 * Register documentation resources for the Nylas API
 */
export function registerDocsResources(server: McpServer) {
  // Register resource for Email API documentation
  server.resource(
    "email-api-docs",
    "nylas://docs/email",
    async (uri) => ({
      contents: [{
        uri: uri.href,
        text: `# Nylas Email API

The Nylas Email API allows you to read, send, and organize emails across multiple providers.

## Key Features

- **Read Emails**: Fetch emails from the user's inbox, sent folder, or custom folders/labels
- **Send Emails**: Compose and send emails with attachments and rich formatting
- **Search**: Search emails by various criteria
- **Thread Management**: Group related emails into threads
- **Labels/Folders**: Organize emails with labels or folders
- **Attachments**: Upload and download email attachments
- **Drafts**: Create, update, and manage email drafts

## Core Endpoints

- GET /messages - List messages
- GET /messages/{id} - Get a specific message
- POST /messages - Send a new message
- PUT /messages/{id} - Update a message
- DELETE /messages/{id} - Delete a message
- GET /threads - List threads
- GET /threads/{id} - Get a specific thread

## Primary Resources

- **Message**: An individual email message
- **Thread**: A collection of related messages
- **Attachment**: A file attached to a message
- **Draft**: An unsent message

## Webhooks and Events

Nylas can notify your application in real-time when emails are received, updated, or deleted through webhooks.`,
        mimeType: "text/markdown"
      }]
    })
  );

  // Register resource for Calendar API documentation
  server.resource(
    "calendar-api-docs",
    "nylas://docs/calendar",
    async (uri) => ({
      contents: [{
        uri: uri.href,
        text: `# Nylas Calendar API

The Nylas Calendar API allows you to read, create, update, and delete calendar events across multiple providers.

## Key Features

- **Events Management**: Create, read, update, and delete calendar events
- **Calendars**: Manage multiple calendars
- **Attendees**: Invite and manage event participants
- **Availability**: Check for free/busy times
- **Recurring Events**: Create and manage recurring event patterns
- **Reminders**: Set up notifications for upcoming events
- **Time Zone Support**: Handle events across different time zones

## Core Endpoints

- GET /events - List events
- GET /events/{id} - Get a specific event
- POST /events - Create a new event
- PUT /events/{id} - Update an event
- DELETE /events/{id} - Delete an event
- GET /calendars - List calendars
- GET /calendars/{id} - Get a specific calendar

## Primary Resources

- **Event**: A calendar event with time, location, and participants
- **Calendar**: A collection of events
- **Participant**: An attendee of an event
- **Free/Busy**: Availability information

## Webhooks and Events

Nylas can notify your application in real-time when calendar events are created, updated, or deleted through webhooks.`,
        mimeType: "text/markdown"
      }]
    })
  );

  // Register resource for Contacts API documentation
  server.resource(
    "contacts-api-docs",
    "nylas://docs/contacts",
    async (uri) => ({
      contents: [{
        uri: uri.href,
        text: `# Nylas Contacts API

The Nylas Contacts API allows you to read, create, update, and delete contacts across multiple providers.

## Key Features

- **Contacts Management**: Create, read, update, and delete contacts
- **Groups/Lists**: Organize contacts into groups or lists
- **Search**: Find contacts by name, email, or other attributes
- **Sync**: Keep contacts in sync across different platforms
- **Rich Data**: Store detailed contact information including email, phone, address, etc.

## Core Endpoints

- GET /contacts - List contacts
- GET /contacts/{id} - Get a specific contact
- POST /contacts - Create a new contact
- PUT /contacts/{id} - Update a contact
- DELETE /contacts/{id} - Delete a contact

## Primary Resources

- **Contact**: A person with contact information
- **Group**: A collection of contacts (supported by some providers)

## Webhooks and Events

Nylas can notify your application in real-time when contacts are created, updated, or deleted through webhooks.`,
        mimeType: "text/markdown"
      }]
    })
  );

  // Register resource for Webhook documentation
  server.resource(
    "webhooks-docs",
    "nylas://docs/webhooks",
    async (uri) => ({
      contents: [{
        uri: uri.href,
        text: `# Nylas Webhooks

Nylas Webhooks allow your application to receive real-time notifications when data changes in a user's account.

## Key Features

- **Real-time Updates**: Get notified immediately when data changes
- **Filtered Notifications**: Subscribe to specific types of events
- **Reduced API Calls**: Eliminate polling for changes
- **Secure Delivery**: Verify webhook authenticity with signatures

## Setting Up Webhooks

1. **Create Webhook**: Register a webhook URL with Nylas
2. **Configure Triggers**: Specify which events should trigger notifications
3. **Handle Notifications**: Process incoming webhook payloads
4. **Verify Signatures**: Ensure webhooks are authentic using the provided signature

## Event Types

- **message.created**: A new email message was received
- **message.updated**: An email message was updated
- **message.deleted**: An email message was deleted
- **thread.replied**: A reply was added to a thread
- **calendar.created**: A calendar was created
- **event.created**: A calendar event was created
- **event.updated**: A calendar event was updated
- **event.deleted**: A calendar event was deleted
- **contact.created**: A contact was created
- **contact.updated**: A contact was updated
- **contact.deleted**: A contact was deleted

## Webhook Management

Webhooks can be created, updated, and deleted through the Nylas Dashboard or API.`,
        mimeType: "text/markdown"
      }]
    })
  );

  // Register documentation for a specific resource by name
  server.resource(
    "docs-by-topic",
    new ResourceTemplate("nylas://docs/{topic}", { list: undefined }),
    async (uri, { topic }) => {
      // Convert topic to string if it's an array
      const topicStr = typeof topic === 'string' ? topic : topic[0];
      
      // Map of topics to their content
      const topics: Record<string, string> = {
        "authentication": `# Nylas Authentication

Nylas uses OAuth 2.0 for authentication. This secure protocol allows users to grant your application access to their email, calendar, and contacts data without sharing their passwords.

## Authentication Flow

1. **Redirect to Nylas**: Your application redirects the user to the Nylas authorization page
2. **User Authorization**: The user logs in to their email provider and authorizes your application
3. **Redirect Back**: Nylas redirects back to your application with an authorization code
4. **Token Exchange**: Your server exchanges the code for an access token
5. **API Access**: Use the access token to make API requests on behalf of the user

## Security Best Practices

- Store tokens securely, treat them like passwords
- Implement token refresh logic for long-lived access
- Use HTTPS for all API requests
- Never expose your client secret in client-side code
- Implement proper token revocation when users disconnect

## Native Authentication

For some providers, Nylas also offers a native authentication option that allows users to enter their credentials directly in your application.`,

        "pagination": `# Pagination in Nylas API

Most Nylas API endpoints that return collections of resources support pagination to efficiently handle large result sets.

## How Pagination Works

Nylas uses cursor-based pagination for consistent results when data is changing:

1. **Initial Request**: Make a request without pagination parameters
2. **Response**: The API returns a batch of results and pagination metadata
3. **Next Page**: Use the \`offset\` parameter from the response to fetch the next page
4. **Continue**: Repeat until all desired results are retrieved or no more results are available

## Pagination Parameters

- **limit**: Number of items to return (default and max values vary by endpoint)
- **offset**: Cursor for the next page of results

## Example Response with Pagination

\`\`\`json
{
  "data": [
    // Resource objects
  ],
  "next_cursor": "ZGF0ZT0xNjQ2NjE0ODAwMDAwJnJvd0lkPTEwMDA=",
  "has_more": true
}
\`\`\`

## Efficient Pagination

- Use appropriate limit values for your use case
- Only fetch as many pages as needed
- Consider implementing virtual scrolling for large datasets
- Cache results when appropriate`,

        "rate-limits": `# Nylas API Rate Limits

Nylas implements rate limits to ensure fair usage of the platform and maintain service stability.

## Rate Limit Structure

Nylas uses a token bucket system for rate limiting:

- Each endpoint has a specific rate limit
- Rate limits are applied per user account
- Some endpoints have higher limits than others based on their usage patterns

## Rate Limit Headers

When you make API requests, Nylas includes rate limit information in the response headers:

- **X-RateLimit-Limit**: Total number of requests allowed in the current time window
- **X-RateLimit-Remaining**: Number of requests remaining in the current time window
- **X-RateLimit-Reset**: Time (in seconds) until the rate limit resets

## Handling Rate Limits

When you exceed a rate limit, Nylas returns a 429 Too Many Requests status code. Best practices for handling rate limits:

1. Check the rate limit headers in each response
2. Implement exponential backoff when you receive a 429 response
3. Spread requests evenly over time when possible
4. For bulk operations, use batch endpoints where available
5. Cache data when appropriate to reduce API calls

## Rate Limit Increases

If your application requires higher rate limits, you can contact Nylas support to discuss your needs and possible solutions.`,

        "errors": `# Nylas API Error Handling

Understanding and properly handling Nylas API errors will help create a robust integration.

## Error Format

Nylas API errors follow a consistent format:

\`\`\`json
{
  "error": {
    "type": "invalid_request_error",
    "message": "A human-readable description of the error",
    "param": "Optional parameter that caused the error"
  }
}
\`\`\`

## Common Error Types

- **invalid_request_error**: The request was malformed or contained invalid parameters
- **authentication_error**: Authentication failed (invalid token, expired token, etc.)
- **resource_not_found_error**: The requested resource does not exist
- **rate_limit_error**: You have exceeded the rate limit for the endpoint
- **provider_error**: The email provider returned an error
- **internal_error**: An unexpected error occurred on the Nylas servers

## HTTP Status Codes

- **400** Bad Request: Invalid request parameters
- **401** Unauthorized: Authentication failed
- **403** Forbidden: Insufficient permissions
- **404** Not Found: Resource not found
- **429** Too Many Requests: Rate limit exceeded
- **500** Internal Server Error: Unexpected server error
- **503** Service Unavailable: Temporary server unavailability

## Error Handling Best Practices

1. Parse the error type and message to determine the appropriate action
2. Implement retries with exponential backoff for transient errors (429, 500, 503)
3. Log errors for troubleshooting
4. Handle authentication errors by refreshing tokens or prompting for re-authentication
5. Provide clear feedback to users when errors occur`
      };
      
      // Return the content for the requested topic, or a not found message
      const content = topics[topicStr] || `# Topic Not Found\n\nThe requested topic "${topicStr}" is not available.`;
      
      return {
        contents: [{
          uri: uri.href,
          text: content,
          mimeType: "text/markdown"
        }]
      };
    }
  );
}
```

--------------------------------------------------------------------------------
/nylas-code-samples/Auth/Hosted/index.md:
--------------------------------------------------------------------------------

```markdown
Nylas v3 introduces a Hosted OAuth system that completely replaces v2 Hosted Auth. The new Hosted OAuth system is OAuth 2.0-compliant, and offers multiple ways to authorize requests after you complete the authentication process. Nylas also offers PKCE options for use with single page applications (SPAs) and mobile apps.

OAuth access tokens expire after one hour, so for most applications, Nylas recommends authenticating end users with OAuth, then using an application API key to authorize requests so you don't need to worry about refresh tokens. You can also choose to receive a refresh token during the authentication process, then use it to get a new access token when an older one expires.

To access your end users' data using pure OAuth, pass the access token as the Bearer token in your request's auth header.

See [Authentication in Nylas v3](https://developer.nylas.com/docs/v3/auth/) and the [Authentication references](https://developer.nylas.com/docs/api/v3/admin/#tag--Authentication-APIs) for more details.

### New Hosted OAuth endpoints

- Revoke an OAuth token: [`POST /v3/connect/revoke`](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/connect/revoke)

### Migrated Hosted auth endpoints

- Hosted auth - Authenticate user → Hosted OAuth - Authorization request (`GET /oauth/authorize` → [`GET /v3/connect/auth`](https://developer.nylas.com/docs/api/v3/admin/#get-/v3/connect/auth))
- Hosted auth - Send authorization code → Hosted OAuth - Token exchange (`POST /oauth/token` → [`POST /v3/connect/token`](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/connect/token))
- Get token information: `POST /a/<NYLAS_CLIENT_ID>/accounts/<NYLAS_ACCOUNT_ID>/token-info` → [`GET /v3/connect/tokeninfo`](https://developer.nylas.com/docs/api/v3/admin/#get-/v3/connect/tokeninfo)

### Deprecated Hosted auth endpoints

- Revoke all access tokens: `POST /a/<NYLAS_CLIENT_ID>/accounts/<NYLAS_ACCOUNT_ID>/revoke-all`

### Start a Hosted OAuth authorization request

`GET /oauth/authorize` → [`GET /v3/connect/auth`](https://developer.nylas.com/docs/api/v3/admin/#get-/v3/connect/auth)

```Node
import 'dotenv/config'
import express from 'express'
import Nylas from 'nylas'

const config = {
  clientId: process.env.NYLAS_CLIENT_ID,
  callbackUri: "http://localhost:3000/oauth/exchange",
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas({ 
  apiKey: config.apiKey, 
  apiUri: config.apiUri,
})

const app = express()
const port = 3000

// Route to initialize authentication.
app.get('/nylas/auth', (req, res) => {
  const authUrl = nylas.auth.urlForOAuth2({
    clientId: config.clientId,
    provider: 'google',
    redirectUri: config.redirectUri,
    loginHint: 'email_to_connect',
    accessType: 'offline',
  })

  res.redirect(authUrl)
})   
```

```Java
get("/nylas/auth", (request, response) -> {
  List<String> scope = new ArrayList<>();
  scope.add("https://www.googleapis.com/auth/calendar");

  UrlForAuthenticationConfig config = new UrlForAuthenticationConfig("<NYLAS_CLIENT_ID>",
      "http://localhost:4567/oauth/exchange",
      AccessType.ONLINE,
      AuthProvider.GOOGLE,
      Prompt.DETECT,
      scope,
      true,
      "sQ6vFQN",
      "[email protected]");

  String url = nylas.auth().urlForOAuth2(config);
  
  response.redirect(url);
  return null;
});   
        
get("/oauth/exchange", (request, response) -> {
  String code = request.queryParams("code");

  if(code == null) { response.status(401);}
  assert code != null;

  CodeExchangeRequest codeRequest = new CodeExchangeRequest(
      "http://localhost:4567/oauth/exchange",
      code,
      "<NYLAS_CLIENT_ID>",
      null,
      null);

  try{
    CodeExchangeResponse codeResponse = nylas.auth().exchangeCodeForToken(codeRequest);

    request.session().attribute("grant_id", codeResponse.getGrantId());

    return "%s".formatted(codeResponse.getGrantId());
  }catch(Exception e){
    return  "%s".formatted(e);
  }
});           
```

```Python
@app.route("/nylas/auth", methods=["GET"])
def login():
  if session.get("grant_id") is None:
    config = URLForAuthenticationConfig({"client_id": "<NYLAS_CLIENT_ID>", 
        "redirect_uri" : "http://localhost:5000/oauth/exchange"})

    url = nylas.auth.url_for_oauth2(config)
    return redirect(url)
  else:
    return f'{session["grant_id"]}'

@app.route("/oauth/exchange", methods=["GET"])
def authorized():
  if session.get("grant_id") is None:
    code = request.args.get("code")

    exchangeRequest = CodeExchangeRequest({"redirect_uri": "http://localhost:5000/oauth/exchange",
        "code": code, "client_id": "<NYLAS_CLIENT_ID>"})

    exchange = nylas.auth.exchange_code_for_token(exchangeRequest)
    session["grant_id"] = exchange.grant_id

    return redirect(url_for("login"))
```

```Ruby
get '/nylas/auth' do
  config = {
    client_id: '<NYLAS_CLIENT_ID>',
    provider: 'google',
    redirect_uri: 'http://localhost:4567/oauth/exchange',
    login_hint: '[email protected]',
    access_type: 'offline'
  }

  url = nylas.auth.url_for_oauth2(config)
  redirect url
end   


get '/oauth/exchange' do
  code = params[:code]
  status 404 if code.nil?

  begin
    response = nylas.auth.exchange_code_for_token({
        client_id: '<NYLAS_CLIENT_ID>',
        redirect_uri: 'http://localhost:4567/oauth/exchange',
        code: code})
  rescue StandardError
    status 500
  else
    response[:grant_id]
    response[:email]
    session[:grant_id] = response[:grant_id]
  end
end
```

```API
curl -X GET "https://api.us.nylas.com/v3/connect/auth?client_id=<CLIENT_ID>&provider=<PROVIDER>&redirect_uri=<REDIRECT_URI>&response_type=<RESPONSE>"
```

### Get token information

`POST /a/<NYLAS_CLIENT_ID>/accounts/<NYLAS_ACCOUNT_ID>/token-info` → [`GET /v3/connect/tokeninfo`](https://developer.nylas.com/docs/api/v3/admin/#get-/v3/connect/tokeninfo)

```Node
import 'dotenv/config'
import Nylas from 'nylas'

// Configure the Nylas SDK with your API key and server URL
const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

const revokeToken = async () => {
  try {
    const token = process.env.TOKEN
    const response = await nylas.auth.accessTokenInfo(token)
    
    console.log('Token Revoked:', response)
  } catch (error) {
    console.error('Error removing connector:', error)
  }
}

revokeToken()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class GetTokenInfo {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    Response<TokenInfoResponse> token = nylas.auth().idTokenInfo("<ACCESS_TOKEN_ID>");
    
    System.out.println(token);
  }
}
```

```Python
import sys
from nylas import Client

nylas = Client(
    '<NYLAS_API_KEY>',
    '<NYLAS_API_URI>'
)

request = nylas.auth.id_token_info(
    '<ACCESS_TOKEN_ID>',
)

print(request)
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(
   api_key: "<NYLAS_API_KEY>"
)

query_params = {
    id_token: "<ACCESS_TOKEN_ID>"
}

token_info = nylas.auth.access_token_info(query_params: query_params)

puts token_info
```

```API
curl --request GET \
  --url 'https://api.us.nylas.com/v3/connect/tokeninfo?id_token=<ACCESS_TOKEN_ID>&access_token=<NYLAS_ACCESS_TOKEN>' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
```

### Exchange tokens

`POST /connect/token` → [`POST /v3/connect/token`](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/connect/token)

```Node
app.get('/oauth/exchange', async (req, res) => {
  console.log(res.status)

  const code = req.query.code

  if (!code) {
    res.status(400).send('No authorization code returned from Nylas')
    return
  }

  try {
    const response = await nylas.auth.exchangeCodeForToken({ 
      clientId: config.clientId,
      redirectUri: config.redirectUri,
      codeVerifier: 'insert-code-challenge-secret-hash',
      code
    })

    const { grantId } = response

    res.status(200)
  } catch (error) {
    console.error('Error exchanging code for token:', error)

    res.status(500).send('Failed to exchange authorization code for token')
  }
})
```

```Java
get("/oauth/exchange", (request, response) -> {
  String code = request.queryParams("code");

  if(code == null) { response.status(401); }

  assert code != null;

  CodeExchangeRequest codeRequest = new CodeExchangeRequest(
      "http://localhost:4567/oauth/exchange",
      code,
      "<NYLAS_CLIENT_ID>",
      "nylas"
  );

  try {
    CodeExchangeResponse codeResponse = nylas.auth().exchangeCodeForToken(codeRequest);

    return "%s".formatted(codeResponse);
  } catch(Exception e) {
    return  "%s".formatted(e);
  }
});
```

```Python
import json
import os
from functools import wraps
from io import BytesIO
from flask import Flask
from nylas import Client

nylas = Client(
    "<NYLAS_CLIENT_ID>",
    "<NYLAS_API_URI>"
)

REDIRECT_CLIENT_URI = 'http://localhost:9000/oauth/exchange'

@flask_app.route("/oauth/exchange", methods=["GET"])

def exchange_code_for_token():
  code_exchange_response = nylas.auth.exchange_code_for_token(
      request={
        "code": request.args.get('code'),
        "client_id": "<NYLAS_CLIENT_ID>",
        "redirect_uri": REDIRECT_CLIENT_URI
      }
  )

  return {
    'email_address': code_exchange_response.email,
    'grant_id': code_exchange_response.grant_id
  }
```

```Ruby
get '/oauth/exchange' do
  code = params[:code]
  status 404 if code.nil?

  begin
    response = nylas.auth.exchange_code_for_token({
      client_id: "<NYLAS_CLIENT_ID>",
      redirect_uri: 'http://localhost:4567/oauth/exchange',
      code: code
    })
  rescue StandardError
    status 500
  else
    grant_id = response[:grant_id]
    email = response[:email]

    "Grant_Id: #{grant_id} \n Email: #{email}"
  end
end
```

```API
curl -X POST "https://api.us.nylas.com/v3/connect/token" \
 -H "accept: application/json"\
 -H "content-type: application/json" \
 -d '{"client_id":"<NYLAS_CLIENT_ID>","client_secret":"<NYLAS_API_KEY>","grant_type":"authorization_code","code":"string","redirect_uri":"https://example.com/callback-handler","code_verifier":"nylas"}' \
```

### Revoke a specific token

You can use the [`POST /v3/connect/revoke` endpoint](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/connect/revoke) to revoke a specific access token.

```Node
import 'dotenv/config'
import Nylas from 'nylas'

// Configure the Nylas SDK with your API key and server URL
const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

const revokeToken = async () => {
  try {
    const token = process.env.TOKEN
    const response = await nylas.auth.revoke(token)
    
    console.log('Token Revoked:', response)
  } catch (error) {
    console.error('Error removing connector:', error)
  }
}

revokeToken()
```

```Java
package org.example;

import com.nylas.NylasClient;
import com.nylas.models.TokenParams;

public class Revoke_Auth_Token {
    public static void main(String[] args) {
        Dotenv dotenv = Dotenv.load();
        NylasClient nylas = new NylasClient.Builder("<V3_TOKEN_API>").build();
        TokenParams token = new TokenParams("<NYLAS_AUTH_TOKEN>");

        try{
        boolean token_status = nylas.auth().revoke(token);
            if(token_status){
                System.out.println("The token was successfully removed");
            }else{
                System.out.println("The token cannot be removed");
            }
        }catch (Exception e){
            System.out.println("Invalid token cannot be removed");
        }
    }
}
```

```Python
from dotenv import load_dotenv
import os
from nylas import Client

load_dotenv()

nylas = Client(
    os.environ.get('NYLAS_API_KEY')
)

try:
    token_state = nylas.auth.revoke("")
    if token_state:
        print("The token was successfully removed")
    else:
        print("The token cannot be removed")
except:
    print("Invalid token cannot be removed")
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
  api_key: "<ACCESS_TOKEN_ID>"
)

token_state = nylas.auth.revoke("<NYLAS_AUTH_TOKEN>")
if(token_state)
  puts "The token was successfully removed"
else
  puts "Invalid token cannot be removed"
end
```

```API
curl -X POST "https://api.us.nylas.com/v3/connect/revoke?token=<NYLAS_AUTH_TOKEN>" \
 -H "accept: application/json" \
```

```

--------------------------------------------------------------------------------
/nylas-code-samples/Calendar/Events/write.md:
--------------------------------------------------------------------------------

```markdown
### Update a specific event

PUT /events/{id} → PUT /v3/grants/{grant_id}/events/{event_id}

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI
}

const nylas = new Nylas(NylasConfig)

async function addParticipantToAndEvent() {
  try {
    const event = await nylas.events.update({
      identifier: process.env.NYLAS_GRANT_ID,
      eventId: process.env.EVENT_ID,
      requestBody: {
        participants: [{
          name: 'Nylas DevRel',
          email: '[email protected]'
        }]
      },
      queryParams: {
        calendarId: process.env.CALENDAR_ID,
      },
    })
  } catch (error) {
    console.error('Error adding participant to event:', error)
  }
}

addParticipantToAndEvent()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class update_calendar_events {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    UpdateEventQueryParams params = new UpdateEventQueryParams("<CALENDAR_ID>", Boolean.FALSE);
    UpdateEventRequest requestBody = new UpdateEventRequest.Builder().location("Nylas' Theatre'").build();

    Response<Event> event = nylas.events().update(
      "<NYLAS_GRANT_ID>",
      "<EVENT_ID>",
      requestBody,
      params);
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
event_id = os.environ.get("EVENT_ID")

event = nylas.events.update(
    grant_id,
    event_id,
    request_body={
      "participants": [{
        "name": "Nylas DevRel",
        "email": "[email protected]"
      }]
    },
    query_params={
      "calendar_id": os.environ.get("CALENDAR_ID")
    }
)

print(event)
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

request_body = {
    location: "Nylas' Theatre",
}

query_params = {
    calendar_id: "<NYLAS_GRANT_ID>"
}

events, _request_ids = nylas.events.update(
        identifier: "<NYLAS_GRANT_ID>", 
        event_id: "<EVENT_ID>", 
        query_params: query_params,
        request_body: request_body)
```

```API
curl --request PUT \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events/<EVENT_ID>?calendar_id=<CALENDAR_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "Birthday Party",
    "busy": true,
    "participants": [{
      "name": "Dorothy Vaughan",
      "email": "[email protected]",
      "comment": "string"
    }],
    "description": "Come ready to skate",
    "when": {
      "time": 1408875644,
      "timezone": "America/New_York"
    },
    "location": "Roller Rink",
    "recurrence": [
      "RRULE:FREQ=WEEKLY;BYDAY=MO",
      "EXDATE:20211011T000000Z"
    ],
    "conferencing": {
      "provider": "WebEx",
      "details": {
        "password": "string",
        "pin": "string",
        "url": "string"
      }
    },
    "reminder_minutes": "[20]",
    "reminder_method": "popup"
}'
```

### Create a specific event

POST /events → POST /v3/grants/{grant_id}/events

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

const now = Math.floor(Date.now() / 1000)

async function createAnEvent() {
  try {
    const event = await nylas.events.create({
      identifier: process.env.NYLAS_GRANT_ID,
      requestBody: {
        title: 'Build With Nylas',
        when: {
          startTime: now,
          endTime: now + 3600,
        }
      },
      queryParams: {
        calendarId: process.env.CALENDAR_ID,
      },
    })

    console.log('Event:', event);
  } catch (error) {
    console.error('Error creating event:', error)
  }
}

createAnEvent()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;

public class create_calendar_events {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    LocalDate today = LocalDate.now();

    Instant sixPmUtc = today.atTime(13, 0).toInstant(ZoneOffset.UTC);

    Instant sixPmUtcPlus = sixPmUtc.plus(30, ChronoUnit.MINUTES);

    long startTime = sixPmUtc.getEpochSecond();
    long endTime = sixPmUtcPlus.getEpochSecond();

    String title = "Let's learn some about the Nylas Java SDK!";
    String location = "Nylas Headquarters";
    String description = "Using the Nylas API with the Java SDK is easy.";

    CreateEventRequest.When.Timespan timespan = new CreateEventRequest.
        When.Timespan.
        Builder(Math.toIntExact(startTime), Math.toIntExact(endTime)).
        build();

    List<CreateEventRequest.Participant> participants_list = new ArrayList<>();

    participants_list.add(new CreateEventRequest.
        Participant("[email protected]", ParticipantStatus.NOREPLY,
        "John Doe", "", ""));

    CreateEventRequest createEventRequest = new CreateEventRequest.Builder(timespan)
        .participants(participants_list)
        .title(title)
        .location(location)
        .description(description)
        .build();

    CreateEventQueryParams createEventQueryParams = new CreateEventQueryParams.Builder("<CALENDAR_ID>").build();

    Event event = nylas.events().create(
        "<NYLAS_GRANT_ID>",
        createEventRequest,
        createEventQueryParams).getData();
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")

events = nylas.events.create(
  grant_id,
  request_body={
    "title": 'Build With Nylas',
    "when": {
      "start_time": 1609372800,
      "end_time": 1609376400
    },
  },
  query_params={
    "calendar_id": os.environ.get("CALENDAR_ID")
  }
)

print(events)
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

query_params = {
    calendar_id: "<NYLAS_GRANT_ID>"
}

today = Date.today
start_time = Time.local(today.year, today.month, today.day, 13, 0, 0).strftime("%s")
end_time = Time.local(today.year, today.month, today.day, 13, 30, 0).strftime("%s")

request_body = {
    when: {
        start_time: start_time.to_i,
        end_time: end_time.to_i
    },
    title: "Let's learn some Nylas Ruby SDK!",
    location: "Nylas' Headquarters",
    description: "Using the Nylas API with the Ruby SDK is easy.",
    participants: [{
        name: "Blag",
        email: "[email protected]", 
        status: 'noreply'
    }]
}

events, _request_ids = nylas.events.create(
        identifier: "<NYLAS_GRANT_ID>", 
        query_params: query_params,
        request_body: request_body)
```

```API
curl --request POST \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=<CALENDAR_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "Annual Philosophy Club Meeting",
    "status": "confirmed",
    "busy": true,
    "participants": [
      {
        "name": "Aristotle",
        "email": "[email protected]"
      },
      {
        "name": "Jane Stephens",
        "email": "[email protected]"
      }
    ],
    "description": "Come ready to talk philosophy!",
    "when": {
      "time": 1700060400
    },
    "location": "New York Public Library, Cave room",
    "recurrence": [
      "RRULE:FREQ=WEEKLY;BYDAY=MO",
      "EXDATE:20211011T000000Z"
  ],
}'
```

### Delete a specific event

DELETE /events/{id} → DELETE /v3/grants/{grant_id}/events/{event_id}

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI
}

const nylas = new Nylas(NylasConfig)

async function deleteEvent() {
  try {
    const event = await nylas.events.destroy({
      identifier: process.env.NYLAS_GRANT_ID,
      eventId: process.env.EVENT_ID,
      queryParams: {
        calendarId: process.env.CALENDAR_ID,
      },
    })

    console.log('Event deleted:', event)
  } catch (error) {
    console.error('Error to delete event:', error)
  }
}

deleteEvent()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class delete_calendar_events {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    DestroyEventQueryParams queryParams = new DestroyEventQueryParams("<CALENDAR_ID>", Boolean.FALSE);

    DeleteResponse event = nylas.events().destroy(
        "<NYLAS_GRANT_ID>",
        "<EVENT_ID>",
        queryParams);
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
event_id = os.environ.get("EVENT_ID")

event = nylas.events.destroy(
    grant_id,
    event_id,
    query_params={
      "calendar_id": os.environ.get("CALENDAR_ID")
    }
)

print(event)
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

query_params = {
  calendar_id: "<NYLAS_GRANT_ID>"
}

result, _request_ids = nylas.events.destroy(
    identifier: "<NYLAS_GRANT_ID>", 
    event_id: "<EVENT_ID>",
    query_params: query_params)

puts result
```

```API
curl --request DELETE \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events/<EVENT_ID>?calendar_id=<CALENDAR_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json'
```

### Send RSVP

POST /send-rsvp → POST /v3/grants/{grant_id}/events/{event_id}/send-rsvp

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI
}

const nylas = new Nylas(NylasConfig)

async function sendEventRSVP() {
  try {
    const event = await nylas.events.update({
      identifier: process.env.NYLAS_GRANT_ID,
      eventId: process.env.EVENT_ID,
      requestBody: {
        participants: [{
          name: 'Nylas DevRel',
          email: '[email protected]',
          status: 'yes',
        }]
      },
      queryParams: {
        calendarId: process.env.CALENDAR_ID,
      },
    })

    console.log('Event RSVP:', event)
  } catch (error) {
    console.error('Error to RSVP participant for event:', error)
  }
}

sendEventRSVP()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class rsvp {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
    SendRsvpRequest requestBody = new SendRsvpRequest(RsvpStatus.YES);
    SendRsvpQueryParams queryParams = new SendRsvpQueryParams("<CALENDAR_ID>");

    DeleteResponse rsvp = nylas.events().sendRsvp(
        "<NYLAS_GRANT_ID>",
        "<EVENT_ID>", 
        requestBody,
        queryParams);
        
    System.out.println(rsvp);
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
event_id = os.environ.get("EVENT_ID")

event = nylas.events.update(
    grant_id,
    event_id,
    request_body={
      "participants": [{
        "name": "Nylas DevRel",
        "email": "[email protected]",
        "status": "yes"
      }]
    },
    query_params={
      "calendar_id": os.environ.get("CALENDAR_ID")
    }
)

print(event)
```

```Ruby
require 'nylas' 

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

request_body = {
  status: "yes"
}

query_params = {
  calendar_id: "<CALENDAR_ID>"
}

event_rsvp = nylas.events.send_rsvp(
    identifier: "<NYLAS_GRANT_ID>",
    event_id: "<EVENT_ID>", 
    request_body: request_body,
    query_params: query_params)
    
puts event_rsvp
```

```API
curl --request POST \
  --url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events/<EVENT_ID>/send-rsvp?calendar_id=<CALENDAR_ID> \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "status": "string"
}'
```

```

--------------------------------------------------------------------------------
/nylas-code-samples/Webhooks/index.md:
--------------------------------------------------------------------------------

```markdown
Follow this general process to upgrade your v2 webhook implementation to v3:

1. On your v2 app, make a v2 [`GET /a/<NYLAS_CLIENT_ID>/webhooks` request](https://developer.nylas.com/docs/api/v2/#get-/a/-client_id-/webhooks) to get a list of your existing webhook subscriptions.
2. Set up a v3 environment as in the guide above, and make sure your auth systems include [any new scopes for v3 webhook triggers](https://developer.nylas.com/docs/v3/notifications/notification-scopes/) you plan to test.
3. Create a grant to test your webhook subscriptions.
4. Set up a webhook URL to receive test data.
    - This endpoint must be able to listen for a [new-subscription verification request](https://developer.nylas.com/docs/v3/notifications/webhooks/#respond-to-webhook-verification-request) from Nylas, and generate a response.
    - If you don't want to run a full development stack, you can use [VS Code port forwarding](https://code.visualstudio.com/docs/editor/port-forwarding) or a service like [Hookdeck](https://hookdeck.com/?referrer=hi-from-the-nylas-docs) instead.
5. Make a v3 [`POST /v3/webhooks` request](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/webhooks) to set up your webhook destination, and include the triggers you want to subscribe to.
6. Test some actions and observe incoming data. You can use the new [Send test event API](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/webhooks/send-test-event) to generate webhook messages.

When your tests meet your requirements, upgrade any code that handles v2 webhooks.

### Changes to webhooks

Nylas v3 includes the following changes to webhooks:

- Webhook notifications now send object data in a single JSON payload, instead of an array of object IDs.
  - Nylas v3 returns truncated webhook notifications for payloads greater than 1MB. Nylas adds the `.truncated` suffix (for example, `message.updated.truncated`) and omits large fields. When this happens, you'll need to re-query the Nylas APIs if you want the complete object.
- You can now set the `description` on a webhook subscription. Use this field as notes to yourself, and information about the subscription and its use.
- You can now set the `notification_email_addresses` on a webhook subscription. Use this to define a list of email addresses Nylas should notify if the webhook has [deliverability issues](https://developer.nylas.com/docs/v3/notifications/webhooks/#failed-webhooks).
- The `callback_uri` used by webhook subscriptions is now called `webhook_url`.
- Webhooks in Nylas v3 are _not_ compatible with Ngrok due to throughput limiting concerns.

### Unchanged webhook triggers

- `calendar.created`
- `calendar.deleted`
- `calendar.updated`
- `contact.deleted`
- `contact.updated`
- `event.created`
- `event.deleted`
- `event.updated`
- `folder.created`
- `folder.deleted`
- `folder.updated`
- `message.created`
- `message.updated`

### New webhook triggers

- `grant.deleted`
- `grant.updated` (Includes re-authentication.)
- `grant.expired`
- `message.send_success` (Scheduled email messages only.)
- `message.send_failed` (Scheduled email messages only.)
- `message.bounce_detected` (Scheduled email messages only.)
- `message.opened` (Tracked email messages only.)
- `message.link_clicked` (Tracked email messages only.)
- `thread.replied` (Tracked email messages only.)

### Migrated webhook triggers

- `account.connected` → `grant.created`

### Deprecated webhook triggers

- `account.invalid` (Use `grant.expired` instead.)
- `account.running`
- `account.stopped`
- `account.sync_error`
- `contact.created` (Use `contact.updated` instead.)
- `job.successful`
- `job.failed`

### New webhooks endpoints

- Get a mock payload: [`POST /v3/webhooks/mock-payload`](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/webhooks/mock-payload)
- Send a test event: [`POST /v3/webhooks/send-test-event`](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/webhooks/send-test-event)
- Rotate a webhook secret: [`POST /v3/webhooks/rotate-secret/<WEBHOOK_ID>`](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/webhooks/rotate-secret/-id-)

### Migrated webhooks endpoints

- Return all webhook destinations for an application: `GET /a/<NYLAS_CLIENT_ID>/webhooks` → [`GET /v3/webhooks`](https://developer.nylas.com/docs/api/v3/admin/#get-/v3/webhooks)
- Create a webhook destination: `POST /a/<NYLAS_CLIENT_ID>/webhooks` → [`POST /v3/webhooks`](https://developer.nylas.com/docs/api/v3/admin/#post-/v3/webhooks)
- Return info for a specific webhook destination: `GET /a/<NYLAS_CLIENT_ID>/webhooks/<WEBHOOK_ID>` → [`GET /v3/webhooks/<WEBHOOK_ID>`](https://developer.nylas.com/docs/api/v3/admin/#get-/v3/webhooks/-id-)
- Update a specific webhook destination: `PUT /a/<NYLAS_CLIENT_ID>/webhooks/<WEBHOOK_ID>` → [`PUT /v3/webhooks/<WEBHOOK_ID>`](https://developer.nylas.com/docs/api/v3/admin/#put-/v3/webhooks/-id-)
- Delete a specific webhook destination: `DELETE /a/<NYLAS_CLIENT_ID>/webhooks/<WEBHOOK_ID>` → [`DELETE /v3/webhooks/<WEBHOOK_ID>`](https://developer.nylas.com/docs/api/v3/admin/#delete-/v3/webhooks/-id-)
- Return application IP addresses → Get webhook source IP addresses (`/a/<NYLAS_CLIENT_ID>/ip_addresses` → [`GET /v3/webhooks/ip-addresses`](https://developer.nylas.com/docs/api/v3/admin/#get-/v3/webhooks/ip-addresses))

### Create a webhook

`POST /webhooks` → `POST /v3/webhooks`

```Node
import 'dotenv/config'
import Nylas from "nylas"

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

const createWebhook = async () => {
  try {
    const webhook = await nylas.webhooks.create({
      requestBody: {
        triggerTypes: [WebhookTriggers.EventCreated],
        webhookUrl: process.env.WEBHOOK_URL,
        description: "My first webhook",
        notificationEmailAddress: process.env.EMAIL,
      }
    })

    console.log("Webhook created:", webhook)
  } catch (error) {
    console.error("Error creating webhook:", error)
  }
}

createWebhook()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;
import com.nylas.resources.Webhooks;
import com.nylas.models.WebhookTriggers;
import java.util.*;

public class webhooks {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    List<WebhookTriggers> triggers = new ArrayList<>();
    triggers.add(WebhookTriggers.EVENT_CREATED);

    CreateWebhookRequest webhookRequest = new CreateWebhookRequest(triggers, "<WEBHOOK_URL>",
        "My first webhook", "<EMAIL_ADDRESS>");

    try {
      Response<WebhookWithSecret> webhook = new Webhooks(nylas).create(webhookRequest);

      System.out.println(webhook.getData());
    } catch (Exception e) {
      System.out.println("Error: " + e);
    }
  }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client
from nylas.models.webhooks import WebhookTriggers

nylas = Client(
  os.environ.get('NYLAS_API_KEY'),
  os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
webhook_url = os.environ.get("WEBHOOK_URL")
email = os.environ.get("EMAIL")

webhook = nylas.webhooks.create(
  request_body={
    "trigger_types": [WebhookTriggers.EVENT_CREATED],
    "webhook_url": webhook_url,
    "description": "My first webhook",
    "notification_email_address": email,
  }
)

print(webhook)
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

request_body = {
  trigger_types: [Nylas::WebhookTrigger::EVENT_CREATED],
  webhook_url: "<WEBHOOK_URL>",
  description: 'My first webhook',
  notification_email_address: ["EMAIL_ADDRESS"]
}

begin
  webhooks, = nylas.webhooks.create(request_body: request_body)
  
  puts "Webhook created: #{webhooks}"
rescue StandardError => ex
  puts "Error creating webhook: #{ex}"
end
```

```API
curl --location 'https://api.us.nylas.com/v3/webhooks/' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--data-raw '{
  "trigger_types": [
    "grant.created",
    "grant.deleted",
    "grant.expired"
  ],
  "description": "local",
  "webhook_url": "<your webhook url>",
  "notification_email_addresses": ["[email protected]", "[email protected]"]
}'
```

### Receive Webhook

POST /webhook → POST /v3/webhook

```Node
import "dotenv/config";
import express from "express";
import Nylas from "nylas";
import crypto from 'crypto';

const config = {
  clientId: process.env.NYLAS_CLIENT_ID,
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
};

const nylas = new Nylas({
  apiKey: config.apiKey,
  apiUri: config.apiUri,
});

const app = express();
const port = 3000;

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

app.get("/callback/nylas", (req, res) => {
  if (req.query.challenge) {
    console.log(`Received challenge code! - ${req.query.challenge}`);
    console.log(`Now returning challenge code! - ${req.query.challenge}`);
    
    return res.send(req.query.challenge);
  }
});
```

```Java
//webhook_info.java
import lombok.Data;

@Data
public class Webhook_Info {
  private String id;
  private String date;
  private String subject;
  private String from_email;
  private String from_name;
}

import spark.ModelAndView;
import static spark.Spark.*;
import spark.template.mustache.MustacheTemplateEngine;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.digest.HmacUtils;

public class ReadWebhooks {
  public static String getHmac(String data, String key) {
    return new HmacUtils("HmacSHA256", key).hmacHex(data);
  }

  public static void main(String[] args) {
    ArrayList<Webhook_Info> array = new ArrayList<Webhook_Info>();

    get("/", (request, response) -> {
      Map<String, Object> model = new HashMap<>();
      model.put("webhooks", array);
      return new ModelAndView(model, "show_webhooks.mustache");
    }, new MustacheTemplateEngine());

    get("/webhook", (request, response) -> request.queryParams("challenge"));

    post("/webhook", (request, response) -> {
      ObjectMapper mapper = new ObjectMapper();

      JsonNode incoming_webhook = mapper.readValue(request.body(), JsonNode.class);

      if (getHmac(request.body(), URLEncoder.
          encode(System.getenv("WEBHOOK_SECRET"), "UTF-8")).
          equals(request.headers("X-Nylas-Signature"))) {
            Webhook_Info new_webhook = new Webhook_Info();

            System.out.println(incoming_webhook.get("data").get("object"));

            new_webhook.setId(incoming_webhook.get("data").
                get("object").get("id").textValue());

            new_webhook.setDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").
                format(new java.util.Date((incoming_webhook.get("data").
                get("object").get("date").asLong() * 1000L))));

            new_webhook.setSubject(incoming_webhook.get("data").
                get("object").get("subject").textValue());

            new_webhook.setFrom_email(incoming_webhook.get("data").
                get("object").get("from").get(0).get("email").textValue());

            new_webhook.setFrom_name(incoming_webhook.get("data").
                get("object").get("from").get(0).get("name").textValue());

            array.add(new_webhook);
      }
      response.status(200);
      return "Webhook Received";
    });
  }
}   
```

```Python
# Import packages
from flask import Flask, request, render_template
import hmac
import hashlib
import os
from dataclasses import dataclass
import pendulum

# Array to hold webhook dataclass
webhooks = []

# Webhook dataclass
@dataclass
class Webhook:
  _id: str
  date: str
  subject: str
  from_email: str
  from_name: str

# Get today’s date
today = pendulum.now()

# Create the Flask app and load the configuration
app = Flask(__name__)

# Read and insert webhook data
@app.route("/webhook", methods=["GET", "POST"])
def webhook():
  # We are connected to Nylas, let’s return the challenge parameter.
  if request.method == "GET" and "challenge" in request.args:
    print(" * Nylas connected to the webhook!")
    return request.args["challenge"]

  if request.method == "POST":
    is_genuine = verify_signature(
        message=request.data,
        key=os.environ["WEBHOOK_SECRET"].encode("utf8"),
        signature=request.headers.get("X-Nylas-Signature"),
    )

    if not is_genuine:
      return "Signature verification failed!", 401
    data = request.get_json()

    hook = Webhook(
        data["data"]["object"]["id"],
        pendulum.from_timestamp(
        data["data"]["object"]["date"], today.timezone.name
        ).strftime("%d/%m/%Y %H:%M:%S"),
        data["data"]["object"]["subject"],
        data["data"]["object"]["from"][0]["email"],
        data["data"]["object"]["from"][0]["name"],
    )

    webhooks.append(hook)

    return "Webhook received", 200

# Main page
@app.route("/")
def index():
  return render_template("main.html", webhooks=webhooks)

# Signature verification
def verify_signature(message, key, signature):
  digest = hmac.new(key, msg=message, digestmod=hashlib.sha256).hexdigest()

  return hmac.compare_digest(digest, signature)

# Run our application
if __name__ == "__main__":
  app.run()
```

```Ruby
# frozen_string_literal: true

# Load gems
require 'nylas'
require 'sinatra'
require 'sinatra/config_file'

webhook = Data.define(:id, :date, :subject, :from_email, :from_name)
webhooks = []

get '/webhook' do
  params['challenge'].to_s if params.include? 'challenge'
end

post '/webhook' do
  # We need to verify that the signature comes from Nylas
  is_genuine = verify_signature(request.body.read, ENV['WEBHOOK_SECRET'],
      request.env['HTTP_X_NYLAS_SIGNATURE'])
  unless is_genuine
    status 401
    'Signature verification failed!'
  end

  # Read the webhook information and store it on the data class.
  request.body.rewind

  model = JSON.parse(request.body.read)

  puts(model["data"]["object"])

  hook = webhook.new(model["data"]["object"]["id"], 
      Time.at(model["data"]["object"]["date"]).strftime("%d/%m/%Y %H:%M:%S"), 
      model["data"]["object"]["subject"], model["data"]["object"]["from"][0]["email"], 
      model["data"]["object"]["from"][0]["name"])

  webhooks.append(hook)

  status 200
  'Webhook received'
end

get '/' do
  puts webhooks
  erb :main, locals: { webhooks: webhooks }
end

# Generate a signature with our client secret and compare it with the one from Nylas.
def verify_signature(message, key, signature)
  digest = OpenSSL::Digest.new('sha256')
  digest = OpenSSL::HMAC.hexdigest(digest, key, message)

  secure_compare(digest, signature)
end

# Compare the keys to see if they are the same
def secure_compare(a_key, b_key)
  return false if a_key.empty? || b_key.empty? || a_key.bytesize != b_key.bytesize

  l = a_key.unpack "C#{a_key.bytesize}"
  res = 0

  b_key.each_byte { |byte| res |= byte ^ l.shift }

  res.zero?
end
```

### Update a webhook

`PUT /webhooks/<webhook_id>` → `PUT /v3/webhooks/<webhook_id>`

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
 apiKey: process.env.NYLAS_API_KEY,
 apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const webhookId = process.env.WEBHOOK_ID

async function updateWebhook() {
  try {
    const folder = await nylas.webhooks.update({
      webhookId,
      requestBody: {
        notificationEmailAddresses: [process.env.EMAIL],
      }
    })

    console.log('Updated Folder:', folder)
  } catch (error) {
    console.error('Error to update folder:', error)
  }
}

updateWebhook()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class webhooks {
    public static void main(String[] args) throws 
    NylasSdkTimeoutError, NylasApiError {

        NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

        UpdateWebhookRequest webhookRequest = new
                UpdateWebhookRequest.Builder().
                description("My updated webhook").
                build();

        Response<Webhook> webhook = nylas.webhooks().update("<WEBHOOK_ID>", 
        webhookRequest);
        System.out.println(webhook.getData());
    }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

webhook_id = os.environ.get("WEBHOOK_ID")
email = os.environ.get("EMAIL")

webhook = nylas.webhooks.update(
  webhook_id,
  request_body={
    "notification_email_addresses": [email],
  }
)

print(webhook)
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
  api_key: "<NYLAS_API_KEY>"
)

request_body = {
    description: 'My updated webhook'
}

webhooks = nylas.webhooks.update(webhook_id: "<WEBHOOK_ID>", 
request_body: request_body)
puts webhooks
```

```API
curl --request PUT \
  --url 'https://api.us.nylas.com/v3/webhooks/<WEBHOOK_ID>' \  
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --data '{
    "notification_email_addresses": [
      "EMAIL_ADDRESS_1",
    ]
  }'
```

### Delete a webhook

`DELETE /webhooks/{id}` → `DELETE /v3/webhooks/{id}`

```Node
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const webhookId = process.env.WEBHOOK_ID

const deleteWebhook = async () => {
  try {
    await nylas.webhooks.destroy({ webhookId })
    console.log(`Webhook with ID ${webhookId} deleted successfully.`)
  } catch (error) {
    console.error(`Error deleting webhook with ID ${webhookId}:`, error)
  }
}


deleteWebhook()
```

```Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class webhooks {
    public static void main(String[] args) throws 
    NylasSdkTimeoutError, NylasApiError {

        NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

        WebhookDeleteResponse deleteResponse = 
        nylas.webhooks().destroy("<WEBHOOK_ID>");
        System.out.println(deleteResponse);
    }
}
```

```Python
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
    os.environ.get('NYLAS_API_KEY'),
    os.environ.get('NYLAS_API_URI')
)

webhook_id = os.environ.get("WEBHOOK_ID")

request = nylas.webhooks.destroy(
  webhook_id,
)

print(request)
```

```Ruby
require 'nylas'

nylas = Nylas::Client.new(
  api_key: "<NYLAS_API_KEY>"
)

status = nylas.webhooks.destroy(webhook_id: "<WEBHOOK_ID>")
puts status
```

```API
curl --request DELETE \
  --url 'https://api.us.nylas.com/v3/webhooks/<WEBHOOK_ID>' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json'
```

```

--------------------------------------------------------------------------------
/src/resources/endpoints.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";

/**
 * Register resources for Nylas API endpoints
 */
export function registerEndpointResources(server: McpServer) {
  // Register a resource that lists all available endpoints
  server.resource(
    "nylas-endpoints",
    "nylas://endpoints",
    async (uri) => ({
      contents: [{
        uri: uri.href,
        text: `# Nylas API Endpoints

This resource provides documentation for Nylas API endpoints organized by category.

## Authentication

- [Authentication](nylas://endpoints/auth)
- [Connected Accounts](nylas://endpoints/connected-accounts)

## Email

- [Messages](nylas://endpoints/messages)
- [Threads](nylas://endpoints/threads)
- [Drafts](nylas://endpoints/drafts)
- [Files & Attachments](nylas://endpoints/attachments)
- [Folders & Labels](nylas://endpoints/folders)
- [Search](nylas://endpoints/search)

## Calendar

- [Calendars](nylas://endpoints/calendars)
- [Events](nylas://endpoints/events)
- [Availability](nylas://endpoints/availability)
- [Free/Busy](nylas://endpoints/free-busy)

## Contacts

- [Contacts](nylas://endpoints/contacts)

## Webhooks

- [Webhooks](nylas://endpoints/webhooks)`,
        mimeType: "text/markdown"
      }]
    })
  );

  // Register a resource for specific endpoint categories
  server.resource(
    "endpoint-category",
    new ResourceTemplate("nylas://endpoints/{category}", { list: undefined }),
    async (uri, { category }) => {
      // Convert category to string if it's an array
      const categoryStr = typeof category === 'string' ? category : category[0];
      
      // Map of categories to their endpoint documentation
      const categories: Record<string, string> = {
        "messages": `# Messages Endpoints

## Overview

The Messages endpoints allow you to read, send, and manage email messages.

## Endpoints

### List Messages

\`GET /v3/grants/{grant_id}/messages\`

Retrieves a list of messages from a user's mailbox.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`limit\` (query): Maximum number of messages to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`sort\` (query): Sort order (default: "-date")
- \`view\` (query): View type ("ids", "count", "expanded")
- \`thread_id\` (query): Filter by thread ID
- \`received_after\` (query): Filter by received date (Unix timestamp)
- \`received_before\` (query): Filter by received date (Unix timestamp)
- \`in\` (query): Filter by folder/label ID

**Response:**
- \`data\`: Array of message objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get Message

\`GET /v3/grants/{grant_id}/messages/{message_id}\`

Retrieves a specific message by ID.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`message_id\` (path): The ID of the message

**Response:**
- Message object with full details

### Send Message

\`POST /v3/grants/{grant_id}/messages\`

Sends a new email message.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`subject\`: Email subject
- \`to\`: Array of recipient objects
- \`cc\` (optional): Array of CC recipient objects
- \`bcc\` (optional): Array of BCC recipient objects
- \`body\`: Email body content
- \`file_ids\` (optional): Array of file IDs to attach

**Response:**
- Created message object

### Update Message

\`PUT /v3/grants/{grant_id}/messages/{message_id}\`

Updates a message's properties.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`message_id\` (path): The ID of the message

**Request Body:**
- \`unread\` (optional): Boolean indicating read/unread state
- \`starred\` (optional): Boolean indicating starred state
- \`folder_id\` (optional): ID of the folder to move the message to

**Response:**
- Updated message object

### Delete Message

\`DELETE /v3/grants/{grant_id}/messages/{message_id}\`

Moves a message to the trash folder.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`message_id\` (path): The ID of the message

**Response:**
- \`status\`: Success status`,

        "threads": `# Threads Endpoints

## Overview

The Threads endpoints allow you to read and manage email threads (conversations).

## Endpoints

### List Threads

\`GET /v3/grants/{grant_id}/threads\`

Retrieves a list of threads from a user's mailbox.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`limit\` (query): Maximum number of threads to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`view\` (query): View type ("ids", "count", "expanded")
- \`received_after\` (query): Filter by received date (Unix timestamp)
- \`received_before\` (query): Filter by received date (Unix timestamp)
- \`in\` (query): Filter by folder/label ID

**Response:**
- \`data\`: Array of thread objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get Thread

\`GET /v3/grants/{grant_id}/threads/{thread_id}\`

Retrieves a specific thread by ID.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`thread_id\` (path): The ID of the thread

**Response:**
- Thread object with full details including messages

### Update Thread

\`PUT /v3/grants/{grant_id}/threads/{thread_id}\`

Updates a thread's properties.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`thread_id\` (path): The ID of the thread

**Request Body:**
- \`unread\` (optional): Boolean indicating read/unread state
- \`starred\` (optional): Boolean indicating starred state
- \`folder_id\` (optional): ID of the folder to move the thread to

**Response:**
- Updated thread object`,

        "drafts": `# Drafts Endpoints

## Overview

The Drafts endpoints allow you to create, read, update, and send email drafts.

## Endpoints

### List Drafts

\`GET /v3/grants/{grant_id}/drafts\`

Retrieves a list of drafts from a user's mailbox.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`limit\` (query): Maximum number of drafts to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset

**Response:**
- \`data\`: Array of draft objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get Draft

\`GET /v3/grants/{grant_id}/drafts/{draft_id}\`

Retrieves a specific draft by ID.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`draft_id\` (path): The ID of the draft

**Response:**
- Draft object with full details

### Create Draft

\`POST /v3/grants/{grant_id}/drafts\`

Creates a new email draft.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`subject\`: Email subject
- \`to\` (optional): Array of recipient objects
- \`cc\` (optional): Array of CC recipient objects
- \`bcc\` (optional): Array of BCC recipient objects
- \`body\` (optional): Email body content
- \`file_ids\` (optional): Array of file IDs to attach

**Response:**
- Created draft object

### Update Draft

\`PUT /v3/grants/{grant_id}/drafts/{draft_id}\`

Updates an existing draft.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`draft_id\` (path): The ID of the draft

**Request Body:**
- \`subject\` (optional): Email subject
- \`to\` (optional): Array of recipient objects
- \`cc\` (optional): Array of CC recipient objects
- \`bcc\` (optional): Array of BCC recipient objects
- \`body\` (optional): Email body content
- \`file_ids\` (optional): Array of file IDs to attach

**Response:**
- Updated draft object

### Delete Draft

\`DELETE /v3/grants/{grant_id}/drafts/{draft_id}\`

Deletes a draft.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`draft_id\` (path): The ID of the draft

**Response:**
- \`status\`: Success status

### Send Draft

\`POST /v3/grants/{grant_id}/drafts/{draft_id}/send\`

Sends an existing draft.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`draft_id\` (path): The ID of the draft

**Response:**
- Sent message object`,

        "attachments": `# Files & Attachments Endpoints

## Overview

The Files & Attachments endpoints allow you to upload, download, and manage files attached to emails.

## Endpoints

### List Files

\`GET /v3/grants/{grant_id}/files\`

Retrieves a list of files attached to emails.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`limit\` (query): Maximum number of files to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`message_id\` (query): Filter by message ID

**Response:**
- \`data\`: Array of file objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get File

\`GET /v3/grants/{grant_id}/files/{file_id}\`

Retrieves metadata for a specific file.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`file_id\` (path): The ID of the file

**Response:**
- File object with metadata

### Download File

\`GET /v3/grants/{grant_id}/files/{file_id}/download\`

Downloads the content of a file.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`file_id\` (path): The ID of the file

**Response:**
- Binary file content with appropriate Content-Type header

### Upload File

\`POST /v3/grants/{grant_id}/files\`

Uploads a new file to be attached to emails.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- Multipart form data with file content

**Response:**
- Uploaded file object with ID for attachment`,

        "folders": `# Folders & Labels Endpoints

## Overview

The Folders & Labels endpoints allow you to manage email organization structures.

## Endpoints

### List Folders

\`GET /v3/grants/{grant_id}/folders\`

Retrieves a list of folders from a user's mailbox.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Response:**
- \`data\`: Array of folder objects

### Get Folder

\`GET /v3/grants/{grant_id}/folders/{folder_id}\`

Retrieves a specific folder by ID.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`folder_id\` (path): The ID of the folder

**Response:**
- Folder object with details

### Create Folder

\`POST /v3/grants/{grant_id}/folders\`

Creates a new folder.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`name\`: Folder name
- \`parent_id\` (optional): Parent folder ID for nested folders

**Response:**
- Created folder object

### Update Folder

\`PUT /v3/grants/{grant_id}/folders/{folder_id}\`

Updates a folder's properties.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`folder_id\` (path): The ID of the folder

**Request Body:**
- \`name\` (optional): New folder name
- \`parent_id\` (optional): New parent folder ID

**Response:**
- Updated folder object

### Delete Folder

\`DELETE /v3/grants/{grant_id}/folders/{folder_id}\`

Deletes a folder.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`folder_id\` (path): The ID of the folder

**Response:**
- \`status\`: Success status`,

        "search": `# Search Endpoints

## Overview

The Search endpoints allow you to search for emails by various criteria.

## Endpoints

### Search Messages

\`GET /v3/grants/{grant_id}/messages/search\`

Searches for messages matching specific criteria.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`q\` (query): Search query string
- \`limit\` (query): Maximum number of results to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`in\` (query): Filter by folder/label ID
- \`date_gt\` (query): Filter by date greater than (Unix timestamp)
- \`date_lt\` (query): Filter by date less than (Unix timestamp)

**Response:**
- \`data\`: Array of matching message objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Search Threads

\`GET /v3/grants/{grant_id}/threads/search\`

Searches for threads matching specific criteria.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`q\` (query): Search query string
- \`limit\` (query): Maximum number of results to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`in\` (query): Filter by folder/label ID
- \`date_gt\` (query): Filter by date greater than (Unix timestamp)
- \`date_lt\` (query): Filter by date less than (Unix timestamp)

**Response:**
- \`data\`: Array of matching thread objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist`,

        "calendars": `# Calendars Endpoints

## Overview

The Calendars endpoints allow you to read and manage calendar containers.

## Endpoints

### List Calendars

\`GET /v3/grants/{grant_id}/calendars\`

Retrieves a list of calendars for a user.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Response:**
- \`data\`: Array of calendar objects

### Get Calendar

\`GET /v3/grants/{grant_id}/calendars/{calendar_id}\`

Retrieves a specific calendar by ID.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`calendar_id\` (path): The ID of the calendar

**Response:**
- Calendar object with details

### Create Calendar

\`POST /v3/grants/{grant_id}/calendars\`

Creates a new calendar.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`name\`: Calendar name
- \`description\` (optional): Calendar description
- \`location\` (optional): Calendar location
- \`timezone\` (optional): Calendar timezone
- \`metadata\` (optional): Custom metadata

**Response:**
- Created calendar object

### Update Calendar

\`PUT /v3/grants/{grant_id}/calendars/{calendar_id}\`

Updates a calendar's properties.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`calendar_id\` (path): The ID of the calendar

**Request Body:**
- \`name\` (optional): New calendar name
- \`description\` (optional): New calendar description
- \`location\` (optional): New calendar location
- \`timezone\` (optional): New calendar timezone
- \`metadata\` (optional): Updated custom metadata

**Response:**
- Updated calendar object

### Delete Calendar

\`DELETE /v3/grants/{grant_id}/calendars/{calendar_id}\`

Deletes a calendar.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`calendar_id\` (path): The ID of the calendar

**Response:**
- \`status\`: Success status`,

        "events": `# Events Endpoints

## Overview

The Events endpoints allow you to read, create, update, and delete calendar events.

## Endpoints

### List Events

\`GET /v3/grants/{grant_id}/events\`

Retrieves a list of events from a user's calendars.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`calendar_id\` (query): Filter by calendar ID
- \`limit\` (query): Maximum number of events to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`start_time\` (query): Filter by start time (Unix timestamp)
- \`end_time\` (query): Filter by end time (Unix timestamp)
- \`show_cancelled\` (query): Include cancelled events (default: false)

**Response:**
- \`data\`: Array of event objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get Event

\`GET /v3/grants/{grant_id}/events/{event_id}\`

Retrieves a specific event by ID.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`event_id\` (path): The ID of the event

**Response:**
- Event object with full details

### Create Event

\`POST /v3/grants/{grant_id}/events\`

Creates a new calendar event.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`calendar_id\`: Calendar ID to create the event in
- \`title\`: Event title
- \`start_time\`: Event start time (Unix timestamp)
- \`end_time\`: Event end time (Unix timestamp)
- \`description\` (optional): Event description
- \`location\` (optional): Event location
- \`participants\` (optional): Array of participant objects
- \`conferencing\` (optional): Conferencing details
- \`busy\` (optional): Whether the event shows as busy (default: true)
- \`reminders\` (optional): Array of reminder objects
- \`recurrence\` (optional): Recurrence rule

**Response:**
- Created event object

### Update Event

\`PUT /v3/grants/{grant_id}/events/{event_id}\`

Updates an existing event.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`event_id\` (path): The ID of the event

**Request Body:**
- \`calendar_id\` (optional): Calendar ID to move the event to
- \`title\` (optional): New event title
- \`start_time\` (optional): New event start time (Unix timestamp)
- \`end_time\` (optional): New event end time (Unix timestamp)
- \`description\` (optional): New event description
- \`location\` (optional): New event location
- \`participants\` (optional): Updated array of participant objects
- \`conferencing\` (optional): Updated conferencing details
- \`busy\` (optional): Whether the event shows as busy
- \`reminders\` (optional): Updated array of reminder objects
- \`recurrence\` (optional): Updated recurrence rule

**Response:**
- Updated event object

### Delete Event

\`DELETE /v3/grants/{grant_id}/events/{event_id}\`

Deletes an event.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`event_id\` (path): The ID of the event

**Response:**
- \`status\`: Success status`,

        "availability": `# Availability Endpoints

## Overview

The Availability endpoints allow you to find free/busy information and available times.

## Endpoints

### Get Availability

\`POST /v3/grants/{grant_id}/calendars/availability\`

Finds available time slots across multiple participants' calendars.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`start_time\`: Start of the time range to check (Unix timestamp)
- \`end_time\`: End of the time range to check (Unix timestamp)
- \`duration_minutes\`: Length of the slots to find
- \`participants\`: Array of participant objects with emails
- \`interval_minutes\` (optional): Interval between potential slots (default: 15)
- \`availability_rule\` (optional): Rule for determining availability ("any" or "all", default: "all")
- \`buffer_minutes\` (optional): Buffer time between meetings (default: 0)
- \`working_hours\` (optional): Working hours constraints
- \`open_hours\` (optional): Open hours constraints

**Response:**
- \`time_slots\`: Array of available time slot objects
- \`timezone\`: Timezone used for calculations`,

        "free-busy": `# Free/Busy Endpoints

## Overview

The Free/Busy endpoints allow you to check when users are free or busy.

## Endpoints

### Get Free/Busy

\`POST /v3/grants/{grant_id}/calendars/free-busy\`

Retrieves free/busy information for users.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`start_time\`: Start of the time range to check (Unix timestamp)
- \`end_time\`: End of the time range to check (Unix timestamp)
- \`emails\`: Array of email addresses to check

**Response:**
- \`free_busy\`: Object mapping emails to arrays of busy time periods`,

        "contacts": `# Contacts Endpoints

## Overview

The Contacts endpoints allow you to read, create, update, and delete contact information.

## Endpoints

### List Contacts

\`GET /v3/grants/{grant_id}/contacts\`

Retrieves a list of contacts.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`limit\` (query): Maximum number of contacts to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`email\` (query): Filter by email address
- \`phone_number\` (query): Filter by phone number
- \`source\` (query): Filter by source of the contact

**Response:**
- \`data\`: Array of contact objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get Contact

\`GET /v3/grants/{grant_id}/contacts/{contact_id}\`

Retrieves a specific contact by ID.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`contact_id\` (path): The ID of the contact

**Response:**
- Contact object with full details

### Create Contact

\`POST /v3/grants/{grant_id}/contacts\`

Creates a new contact.

**Parameters:**
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`given_name\` (optional): First name
- \`middle_name\` (optional): Middle name
- \`surname\` (optional): Last name
- \`nickname\` (optional): Nickname
- \`emails\` (optional): Array of email objects
- \`phone_numbers\` (optional): Array of phone number objects
- \`physical_addresses\` (optional): Array of address objects
- \`web_pages\` (optional): Array of web page objects
- \`notes\` (optional): Notes about the contact
- \`job_title\` (optional): Job title
- \`company_name\` (optional): Company name
- \`picture\` (optional): Profile picture URL
- \`birthday\` (optional): Birthday (Unix timestamp)

**Response:**
- Created contact object

### Update Contact

\`PUT /v3/grants/{grant_id}/contacts/{contact_id}\`

Updates an existing contact.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`contact_id\` (path): The ID of the contact

**Request Body:**
- \`given_name\` (optional): Updated first name
- \`middle_name\` (optional): Updated middle name
- \`surname\` (optional): Updated last name
- \`nickname\` (optional): Updated nickname
- \`emails\` (optional): Updated array of email objects
- \`phone_numbers\` (optional): Updated array of phone number objects
- \`physical_addresses\` (optional): Updated array of address objects
- \`web_pages\` (optional): Updated array of web page objects
- \`notes\` (optional): Updated notes about the contact
- \`job_title\` (optional): Updated job title
- \`company_name\` (optional): Updated company name
- \`picture\` (optional): Updated profile picture URL
- \`birthday\` (optional): Updated birthday (Unix timestamp)

**Response:**
- Updated contact object

### Delete Contact

\`DELETE /v3/grants/{grant_id}/contacts/{contact_id}\`

Deletes a contact.

**Parameters:**
- \`grant_id\` (path): The ID of the grant
- \`contact_id\` (path): The ID of the contact

**Response:**
- \`status\`: Success status`,

        "webhooks": `# Webhooks Endpoints

## Overview

The Webhooks endpoints allow you to set up real-time notifications for changes to user data.

## Endpoints

### List Webhooks

\`GET /v3/applications/{application_id}/webhooks\`

Retrieves a list of webhooks for an application.

**Parameters:**
- \`application_id\` (path): The ID of the application
- \`limit\` (query): Maximum number of webhooks to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset

**Response:**
- \`data\`: Array of webhook objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get Webhook

\`GET /v3/applications/{application_id}/webhooks/{webhook_id}\`

Retrieves a specific webhook by ID.

**Parameters:**
- \`application_id\` (path): The ID of the application
- \`webhook_id\` (path): The ID of the webhook

**Response:**
- Webhook object with full details

### Create Webhook

\`POST /v3/applications/{application_id}/webhooks\`

Creates a new webhook.

**Parameters:**
- \`application_id\` (path): The ID of the application

**Request Body:**
- \`webhook_url\`: URL to send webhook events to
- \`description\` (optional): Description of the webhook
- \`trigger_types\`: Array of event types to trigger the webhook
- \`webhook_secret\` (optional): Secret for securing webhook payloads
- \`grant_id\` (optional): Specific grant ID to monitor (omit for all grants)

**Response:**
- Created webhook object

### Update Webhook

\`PUT /v3/applications/{application_id}/webhooks/{webhook_id}\`

Updates an existing webhook.

**Parameters:**
- \`application_id\` (path): The ID of the application
- \`webhook_id\` (path): The ID of the webhook

**Request Body:**
- \`webhook_url\` (optional): Updated URL to send webhook events to
- \`description\` (optional): Updated description of the webhook
- \`trigger_types\` (optional): Updated array of event types to trigger the webhook
- \`webhook_secret\` (optional): Updated secret for securing webhook payloads
- \`status\` (optional): Updated status ("active" or "disabled")

**Response:**
- Updated webhook object

### Delete Webhook

\`DELETE /v3/applications/{application_id}/webhooks/{webhook_id}\`

Deletes a webhook.

**Parameters:**
- \`application_id\` (path): The ID of the application
- \`webhook_id\` (path): The ID of the webhook

**Response:**
- \`status\`: Success status

### Rotate Webhook Secret

\`POST /v3/applications/{application_id}/webhooks/{webhook_id}/rotate-secret\`

Generates a new secret for a webhook.

**Parameters:**
- \`application_id\` (path): The ID of the application
- \`webhook_id\` (path): The ID of the webhook

**Response:**
- \`webhook_secret\`: The new webhook secret`,
        
        "auth": `# Authentication Endpoints

## Overview

The Authentication endpoints allow you to initiate the OAuth flow and manage authentication tokens.

## Endpoints

### Generate Authentication URL

\`GET /v3/connect/oauth/authorize\`

Generates a URL to redirect users to for authentication.

**Parameters:**
- \`client_id\` (query): Your application's client ID
- \`redirect_uri\` (query): URL to redirect to after authentication
- \`response_type\` (query): Authentication response type (default: "code")
- \`scopes\` (query): Comma-separated list of permission scopes
- \`state\` (query): Optional state parameter for security
- \`provider\` (query, optional): Email provider ("google", "microsoft", etc.)
- \`login_hint\` (query, optional): User's email address for pre-filling

**Response:**
- Redirect to the authentication URL

### Exchange Code for Token

\`POST /v3/connect/oauth/token\`

Exchanges an authentication code for an access token.

**Request Body:**
- \`client_id\`: Your application's client ID
- \`client_secret\`: Your application's client secret
- \`grant_type\`: Type of grant (use "authorization_code")
- \`code\`: The authorization code received from the redirect
- \`redirect_uri\`: The same redirect URI used in the authorization request

**Response:**
- \`access_token\`: The access token for API requests
- \`token_type\`: Type of token (usually "bearer")
- \`expires_in\`: Time until token expiration (in seconds)
- \`refresh_token\`: Token for obtaining a new access token
- \`scope\`: Granted permission scopes
- \`grant_id\`: ID of the newly created grant

### Refresh Token

\`POST /v3/connect/oauth/token\`

Refreshes an expired access token.

**Request Body:**
- \`client_id\`: Your application's client ID
- \`client_secret\`: Your application's client secret
- \`grant_type\`: Type of grant (use "refresh_token")
- \`refresh_token\`: The refresh token received previously

**Response:**
- \`access_token\`: New access token for API requests
- \`token_type\`: Type of token (usually "bearer")
- \`expires_in\`: Time until token expiration (in seconds)
- \`refresh_token\`: New refresh token
- \`scope\`: Granted permission scopes`,

        "connected-accounts": `# Connected Accounts Endpoints

## Overview

The Connected Accounts endpoints allow you to manage user accounts connected to your application.

## Endpoints

### List Grants

\`GET /v3/applications/{application_id}/grants\`

Retrieves a list of grants (connected accounts) for your application.

**Parameters:**
- \`application_id\` (path): The ID of your application
- \`limit\` (query): Maximum number of grants to return (default: 10, max: 100)
- \`offset\` (query): Pagination offset
- \`provider\` (query, optional): Filter by provider
- \`email\` (query, optional): Filter by email address

**Response:**
- \`data\`: Array of grant objects
- \`next_cursor\`: Cursor for pagination
- \`has_more\`: Boolean indicating if more results exist

### Get Grant

\`GET /v3/applications/{application_id}/grants/{grant_id}\`

Retrieves a specific grant by ID.

**Parameters:**
- \`application_id\` (path): The ID of your application
- \`grant_id\` (path): The ID of the grant

**Response:**
- Grant object with full details

### Delete Grant

\`DELETE /v3/applications/{application_id}/grants/{grant_id}\`

Revokes a grant, disconnecting the user's account.

**Parameters:**
- \`application_id\` (path): The ID of your application
- \`grant_id\` (path): The ID of the grant

**Response:**
- \`status\`: Success status

### Update Grant

\`PUT /v3/applications/{application_id}/grants/{grant_id}\`

Updates properties of a grant.

**Parameters:**
- \`application_id\` (path): The ID of your application
- \`grant_id\` (path): The ID of the grant

**Request Body:**
- \`status\` (optional): New status ("active" or "disabled")
- \`ip_restrictions\` (optional): IP address restrictions
- \`scopes\` (optional): Updated permission scopes

**Response:**
- Updated grant object`
      };
      
      // Return the content for the requested category, or a not found message
      const content = categories[categoryStr] || `# Category Not Found\n\nThe requested endpoint category "${categoryStr}" is not available.`;
      
      return {
        contents: [{
          uri: uri.href,
          text: content,
          mimeType: "text/markdown"
        }]
      };
    }
  );
}
```

--------------------------------------------------------------------------------
/src/tools/index.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

/**
 * Register all tools with the MCP server
 */
export function registerTools(server: McpServer) {
  // Register code generation tools
  registerCodeGenerationTools(server);
  
  // Register API explorer tools
  registerApiExplorerTools(server);
}

/**
 * Register code generation tools
 */
function registerCodeGenerationTools(server: McpServer) {
  // Tool to generate authentication code for a specific language
  server.tool(
    "generate-auth-code",
    {
      language: z.enum(["node", "python", "java", "ruby", "curl"]),
      clientId: z.string().optional(),
      clientSecret: z.string().optional(),
      redirectUri: z.string().optional(),
      scopes: z.array(z.string()).optional()
    },
    async ({ language, clientId, clientSecret, redirectUri, scopes }) => {
      const normalizedLanguage = normalizeLanguage(language);
      const placeholderClientId = clientId || "YOUR_CLIENT_ID";
      const placeholderClientSecret = clientSecret || "YOUR_CLIENT_SECRET";
      const placeholderRedirectUri = redirectUri || "YOUR_REDIRECT_URI";
      const placeholderScopes = scopes || ["email", "calendar", "contacts"];
      
      // Map of languages to their authentication code templates
      const templates: Record<string, string> = {
        "Node": `
// Authentication with Nylas API using Node.js
import { Nylas } from '@nylas/nylas-js';

// Initialize Nylas client
Nylas.config({
  clientId: "${placeholderClientId}",
  clientSecret: "${placeholderClientSecret}",
});

// Generate OAuth URL to redirect the user to
const authUrl = Nylas.urlForAuthentication({
  redirectURI: "${placeholderRedirectUri}",
  scopes: ${JSON.stringify(placeholderScopes)},
});

console.log("Redirect the user to:", authUrl);

// After the user is redirected back to your redirect URI:
// Exchange the authorization code for an access token
async function exchangeCodeForToken(code) {
  try {
    const tokenData = await Nylas.exchangeCodeForToken(code);
    console.log("Access token:", tokenData.accessToken);
    console.log("Grant ID:", tokenData.grantId);
    
    // Now you can use this token to make API calls
    return tokenData;
  } catch (error) {
    console.error("Error exchanging code for token:", error);
  }
}

// Call this function with the code from the URL parameter
// exchangeCodeForToken(codeFromUrl);
`,

        "Python": `
# Authentication with Nylas API using Python
from nylas import Client
import os

# Initialize Nylas client
nylas = Client(
    client_id="${placeholderClientId}",
    client_secret="${placeholderClientSecret}"
)

# Generate OAuth URL to redirect the user to
auth_url = nylas.authentication_url(
    redirect_uri="${placeholderRedirectUri}",
    scopes=${placeholderScopes}
)

print("Redirect the user to:", auth_url)

# After the user is redirected back to your redirect URI:
# Exchange the authorization code for an access token
def exchange_code_for_token(code):
    try:
        token_data = nylas.exchange_code_for_token(code)
        print("Access token:", token_data['access_token'])
        print("Grant ID:", token_data['grant_id'])
        
        # Now you can use this token to make API calls
        return token_data
    except Exception as e:
        print("Error exchanging code for token:", e)

# Call this function with the code from the URL parameter
# exchange_code_for_token(code_from_url)
`,

        "Java": `
// Authentication with Nylas API using Java
import com.nylas.NylasClient;
import com.nylas.models.*;

public class NylasAuth {
    public static void main(String[] args) {
        // Initialize Nylas client
        NylasClient nylas = new NylasClient.Builder("${placeholderClientId}")
            .clientSecret("${placeholderClientSecret}")
            .build();
            
        // Generate OAuth URL to redirect the user to
        String authUrl = nylas.auth().urlForAuthentication(
            "${placeholderRedirectUri}", 
            ${placeholderScopes.map(scope => '"' + scope + '"').join(", ")}
        );
        
        System.out.println("Redirect the user to: " + authUrl);
        
        // After the user is redirected back to your redirect URI:
        // Exchange the authorization code for an access token
        String code = "CODE_FROM_URL_PARAMETER";
        
        try {
            TokenResponse tokenData = nylas.auth().exchangeCodeForToken(code);
            System.out.println("Access token: " + tokenData.getAccessToken());
            System.out.println("Grant ID: " + tokenData.getGrantId());
            
            // Now you can use this token to make API calls
        } catch (Exception e) {
            System.err.println("Error exchanging code for token: " + e.getMessage());
        }
    }
}
`,

        "Ruby": `
# Authentication with Nylas API using Ruby
require 'nylas'

# Initialize Nylas client
nylas = Nylas::Client.new(
  client_id: "${placeholderClientId}",
  client_secret: "${placeholderClientSecret}"
)

# Generate OAuth URL to redirect the user to
auth_url = nylas.auth.authorize_url(
  redirect_uri: "${placeholderRedirectUri}",
  scopes: ${JSON.stringify(placeholderScopes)}
)

puts "Redirect the user to: #{auth_url}"

# After the user is redirected back to your redirect URI:
# Exchange the authorization code for an access token
def exchange_code_for_token(code)
  begin
    token_data = nylas.auth.exchange_code_for_token(code)
    puts "Access token: #{token_data.access_token}"
    puts "Grant ID: #{token_data.grant_id}"
    
    # Now you can use this token to make API calls
    return token_data
  rescue => e
    puts "Error exchanging code for token: #{e.message}"
  end
end

# Call this function with the code from the URL parameter
# exchange_code_for_token(code_from_url)
`,

        "curl": `
# Authentication with Nylas API using curl

# Step 1: Generate an authorization URL (typically done in your backend)
# Users will be redirected to this URL to authorize your application

# Step 2: After authorization, the user is redirected to your redirect URI with a code
# For example: ${placeholderRedirectUri}?code=AUTHORIZATION_CODE

# Step 3: Exchange the authorization code for an access token
curl --request POST \\
  --url "https://api.us.nylas.com/v3/connect/oauth/token" \\
  --header "Content-Type: application/json" \\
  --data '{
    "client_id": "${placeholderClientId}",
    "client_secret": "${placeholderClientSecret}",
    "grant_type": "authorization_code",
    "code": "AUTHORIZATION_CODE_FROM_REDIRECT",
    "redirect_uri": "${placeholderRedirectUri}"
  }'

# Response will contain access_token, refresh_token, grant_id, etc.

# Step 4: Use the access token to make API calls
curl --request GET \\
  --url "https://api.us.nylas.com/v3/grants/GRANT_ID/messages?limit=10" \\
  --header "Content-Type: application/json" \\
  --header "Authorization: Bearer ACCESS_TOKEN"
`
      };
      
      // Get the template for the requested language, or provide an error message
      const template = templates[normalizedLanguage] || 
        `Code generation is not available for ${language}. Available languages are: Node.js, Python, Java, Ruby, and curl.`;
      
      return {
        content: [
          {
            type: "text",
            text: template
          }
        ]
      };
    }
  );
  
  // Tool to generate code for a specific API endpoint
  server.tool(
    "generate-endpoint-code",
    {
      language: z.enum(["node", "python", "java", "ruby", "curl"]),
      endpoint: z.string(),
      method: z.enum(["GET", "POST", "PUT", "DELETE"]).optional(),
      params: z.record(z.any()).optional()
    },
    async ({ language, endpoint, method = "GET", params = {} }) => {
      const normalizedLanguage = normalizeLanguage(language);
      const endpointPath = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
      
      // Construct the endpoint with path parameters
      let formattedEndpoint = endpointPath;
      
      // Replace path parameters with values from params
      Object.keys(params).forEach(key => {
        if (formattedEndpoint.includes(`{${key}}`)) {
          formattedEndpoint = formattedEndpoint.replace(`{${key}}`, params[key]);
          delete params[key]; // Remove used path parameters
        }
      });
      
      // Map of languages to their API code templates
      const templates: Record<string, string> = {
        "Node": `
// ${method} ${endpointPath} using Nylas Node.js SDK
import 'dotenv/config';
import Nylas from '@nylas/nylas-js';

// Initialize the Nylas client
const nylas = new Nylas({
  apiKey: process.env.NYLAS_API_KEY
});

async function callNylasApi() {
  try {
    ${generateNodeCode(method, formattedEndpoint, params)}
    
    console.log(response);
    return response;
  } catch (error) {
    console.error('Error calling Nylas API:', error);
  }
}

callNylasApi();
`,

        "Python": `
# ${method} ${endpointPath} using Nylas Python SDK
from dotenv import load_dotenv
load_dotenv()

import os
from nylas import Client

# Initialize the Nylas client
nylas = Client(
    api_key=os.environ.get('NYLAS_API_KEY')
)

${generatePythonCode(method, formattedEndpoint, params)}

print(response)
`,

        "Java": `
// ${method} ${endpointPath} using Nylas Java SDK
import com.nylas.NylasClient;
import com.nylas.models.*;

public class NylasApiExample {
    public static void main(String[] args) {
        try {
            // Initialize the Nylas client
            NylasClient nylas = new NylasClient.Builder(System.getenv("NYLAS_API_KEY")).build();
            
            ${generateJavaCode(method, formattedEndpoint, params)}
            
            System.out.println(response);
        } catch (Exception e) {
            System.err.println("Error calling Nylas API: " + e.getMessage());
        }
    }
}
`,

        "Ruby": `
# ${method} ${endpointPath} using Nylas Ruby SDK
require 'nylas'
require 'dotenv/load'

# Initialize the Nylas client
nylas = Nylas::Client.new(
  api_key: ENV['NYLAS_API_KEY']
)

${generateRubyCode(method, formattedEndpoint, params)}

puts response
`,

        "curl": `
# ${method} ${endpointPath} using curl
${generateCurlCode(method, formattedEndpoint, params)}
`
      };
      
      // Get the template for the requested language, or provide an error message
      const template = templates[normalizedLanguage] || 
        `Code generation is not available for ${language}. Available languages are: Node.js, Python, Java, Ruby, and curl.`;
      
      return {
        content: [
          {
            type: "text",
            text: template
          }
        ]
      };
    }
  );
}

/**
 * Register API explorer tools
 */
function registerApiExplorerTools(server: McpServer) {
  // Tool to search the Nylas API documentation
  server.tool(
    "search-api-docs",
    {
      query: z.string(),
      category: z.enum(["email", "calendar", "contacts", "auth", "webhooks"]).optional()
    },
    async ({ query, category }) => {
      // Normalize the query for search
      const normalizedQuery = query.toLowerCase();
      
      // Define search result templates
      const searchResults: Record<string, string[]> = {
        "email": [
          `### Messages API
The Messages API allows you to read, send, and search email messages.
Key endpoints:
- GET /v3/grants/{grant_id}/messages - List messages
- GET /v3/grants/{grant_id}/messages/{message_id} - Get a specific message
- POST /v3/grants/{grant_id}/messages - Send a message`,
          
          `### Threads API
The Threads API allows you to manage email conversations.
Key endpoints:
- GET /v3/grants/{grant_id}/threads - List threads
- GET /v3/grants/{grant_id}/threads/{thread_id} - Get a specific thread`,
          
          `### Drafts API
The Drafts API allows you to create and manage email drafts.
Key endpoints:
- GET /v3/grants/{grant_id}/drafts - List drafts
- POST /v3/grants/{grant_id}/drafts - Create a draft
- POST /v3/grants/{grant_id}/drafts/{draft_id}/send - Send a draft`
        ],
        
        "calendar": [
          `### Calendars API
The Calendars API allows you to manage calendar containers.
Key endpoints:
- GET /v3/grants/{grant_id}/calendars - List calendars
- GET /v3/grants/{grant_id}/calendars/{calendar_id} - Get a specific calendar`,
          
          `### Events API
The Events API allows you to create and manage calendar events.
Key endpoints:
- GET /v3/grants/{grant_id}/events - List events
- POST /v3/grants/{grant_id}/events - Create an event
- PUT /v3/grants/{grant_id}/events/{event_id} - Update an event`,
          
          `### Availability API
The Availability API helps find available time slots.
Key endpoints:
- POST /v3/grants/{grant_id}/calendars/availability - Find available time slots`
        ],
        
        "contacts": [
          `### Contacts API
The Contacts API allows you to manage contact information.
Key endpoints:
- GET /v3/grants/{grant_id}/contacts - List contacts
- GET /v3/grants/{grant_id}/contacts/{contact_id} - Get a specific contact
- POST /v3/grants/{grant_id}/contacts - Create a contact`
        ],
        
        "auth": [
          `### Authentication API
The Authentication API handles OAuth flows.
Key endpoints:
- GET /v3/connect/oauth/authorize - Start OAuth flow
- POST /v3/connect/oauth/token - Exchange code for token or refresh token`,
          
          `### Grants API
The Grants API manages connected accounts.
Key endpoints:
- GET /v3/applications/{application_id}/grants - List connected accounts
- GET /v3/applications/{application_id}/grants/{grant_id} - Get a specific connected account`
        ],
        
        "webhooks": [
          `### Webhooks API
The Webhooks API allows setting up real-time notifications.
Key endpoints:
- GET /v3/applications/{application_id}/webhooks - List webhooks
- POST /v3/applications/{application_id}/webhooks - Create a webhook
- DELETE /v3/applications/{application_id}/webhooks/{webhook_id} - Delete a webhook`
        ]
      };
      
      // If a category is specified, search only in that category
      if (category) {
        const categoryResults = searchResults[category] || [];
        const matches = categoryResults.filter(result => 
          result.toLowerCase().includes(normalizedQuery)
        );
        
        if (matches.length > 0) {
          return {
            content: [
              {
                type: "text",
                text: `# Search results for "${query}" in ${category} API\n\n${matches.join('\n\n')}`
              }
            ]
          };
        } else {
          return {
            content: [
              {
                type: "text",
                text: `No results found for "${query}" in the ${category} API. Try a different search term or category.`
              }
            ]
          };
        }
      }
      
      // If no category is specified, search in all categories
      const allResults: string[] = [];
      
      Object.entries(searchResults).forEach(([category, results]) => {
        const categoryMatches = results.filter(result => 
          result.toLowerCase().includes(normalizedQuery)
        );
        
        if (categoryMatches.length > 0) {
          allResults.push(`## ${category.charAt(0).toUpperCase() + category.slice(1)} API\n\n${categoryMatches.join('\n\n')}`);
        }
      });
      
      if (allResults.length > 0) {
        return {
          content: [
            {
              type: "text",
              text: `# Search results for "${query}"\n\n${allResults.join('\n\n')}`
            }
          ]
        };
      } else {
        return {
          content: [
            {
              type: "text",
              text: `No results found for "${query}". Try a different search term.`
            }
          ]
        };
      }
    }
  );
}

/**
 * Normalize language names for code generation
 */
function normalizeLanguage(language: string): string {
  const langMap: Record<string, string> = {
    'node': 'Node',
    'nodejs': 'Node',
    'javascript': 'Node',
    'js': 'Node',
    'python': 'Python',
    'py': 'Python',
    'java': 'Java',
    'ruby': 'Ruby',
    'rb': 'Ruby',
    'curl': 'curl',
    'api': 'curl',
    'rest': 'curl'
  };
  
  return langMap[language.toLowerCase()] || language;
}

/**
 * Generate Node.js code for the API endpoint
 */
function generateNodeCode(method: string, endpoint: string, params: Record<string, any>): string {
  const parts = endpoint.split('/');
  let resourceType = '';
  let functionName = '';
  let grantId = 'process.env.NYLAS_GRANT_ID';
  let resourceId = '';
  
  // Try to determine the resource type and function name
  if (parts.length >= 3) {
    if (parts[1] === 'v3' && parts[2] === 'grants') {
      if (parts.length >= 5) {
        resourceType = parts[4]; // like 'messages', 'events', etc.
        
        if (parts.length >= 6) {
          resourceId = parts[5];
          
          if (parts.length >= 7 && parts[6] === 'send') {
            functionName = 'send';
          }
        }
      }
    }
  }
  
  // Handle different HTTP methods
  switch (method) {
    case 'GET':
      if (resourceId) {
        // Get a specific resource
        return `const response = await nylas.${resourceType}.find({
      identifier: ${grantId},
      ${resourceType.slice(0, -1)}Id: "${resourceId}",
      ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n      ')}
    });`;
      } else {
        // List resources
        return `const response = await nylas.${resourceType}.list({
      identifier: ${grantId},
      ${Object.keys(params).length > 0 ? `queryParams: {
        ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n        ')}
      }` : ''}
    });`;
      }
    
    case 'POST':
      if (functionName === 'send') {
        // Send a draft
        return `const response = await nylas.${resourceType}.send({
      identifier: ${grantId},
      ${resourceType.slice(0, -1)}Id: "${resourceId}"
    });`;
      } else {
        // Create a resource
        return `const response = await nylas.${resourceType}.create({
      identifier: ${grantId},
      ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n      ')}
    });`;
      }
    
    case 'PUT':
      // Update a resource
      return `const response = await nylas.${resourceType}.update({
      identifier: ${grantId},
      ${resourceType.slice(0, -1)}Id: "${resourceId}",
      ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n      ')}
    });`;
    
    case 'DELETE':
      // Delete a resource
      return `const response = await nylas.${resourceType}.destroy({
      identifier: ${grantId},
      ${resourceType.slice(0, -1)}Id: "${resourceId}"
    });`;
    
    default:
      return `// No code generation available for this endpoint
const response = "Please refer to the Nylas API documentation for this endpoint.";`;
  }
}

/**
 * Generate Python code for the API endpoint
 */
function generatePythonCode(method: string, endpoint: string, params: Record<string, any>): string {
  const parts = endpoint.split('/');
  let resourceType = '';
  let functionName = '';
  let grantId = 'os.environ.get("NYLAS_GRANT_ID")';
  let resourceId = '';
  
  // Try to determine the resource type and function name
  if (parts.length >= 3) {
    if (parts[1] === 'v3' && parts[2] === 'grants') {
      if (parts.length >= 5) {
        resourceType = parts[4]; // like 'messages', 'events', etc.
        
        if (parts.length >= 6) {
          resourceId = parts[5];
          
          if (parts.length >= 7 && parts[6] === 'send') {
            functionName = 'send';
          }
        }
      }
    }
  }
  
  // Handle different HTTP methods
  switch (method) {
    case 'GET':
      if (resourceId) {
        // Get a specific resource
        return `# Get a specific ${resourceType.slice(0, -1)}
response = nylas.${resourceType}.find(
    ${grantId},
    "${resourceId}"${Object.keys(params).length > 0 ? `,
    query_params={
        ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n        ')}
    }` : ''}
)`;
      } else {
        // List resources
        return `# List ${resourceType}
response = nylas.${resourceType}.list(
    ${grantId}${Object.keys(params).length > 0 ? `,
    query_params={
        ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n        ')}
    }` : ''}
)`;
      }
    
    case 'POST':
      if (functionName === 'send') {
        // Send a draft
        return `# Send a draft
response = nylas.${resourceType}.send(
    ${grantId},
    "${resourceId}"
)`;
      } else {
        // Create a resource
        return `# Create a new ${resourceType.slice(0, -1)}
response = nylas.${resourceType}.create(
    ${grantId},
    {
        ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n        ')}
    }
)`;
      }
    
    case 'PUT':
      // Update a resource
      return `# Update a ${resourceType.slice(0, -1)}
response = nylas.${resourceType}.update(
    ${grantId},
    "${resourceId}",
    {
        ${Object.entries(params).map(([key, value]) => `"${key}": ${JSON.stringify(value)}`).join(',\n        ')}
    }
)`;
    
    case 'DELETE':
      // Delete a resource
      return `# Delete a ${resourceType.slice(0, -1)}
response = nylas.${resourceType}.destroy(
    ${grantId},
    "${resourceId}"
)`;
    
    default:
      return `# No code generation available for this endpoint
response = "Please refer to the Nylas API documentation for this endpoint."`;
  }
}

/**
 * Generate Java code for the API endpoint
 */
function generateJavaCode(method: string, endpoint: string, params: Record<string, any>): string {
  const parts = endpoint.split('/');
  let resourceType = '';
  let functionName = '';
  let grantId = 'System.getenv("NYLAS_GRANT_ID")';
  let resourceId = '';
  
  // Try to determine the resource type and function name
  if (parts.length >= 3) {
    if (parts[1] === 'v3' && parts[2] === 'grants') {
      if (parts.length >= 5) {
        resourceType = parts[4]; // like 'messages', 'events', etc.
        resourceType = resourceType.charAt(0).toUpperCase() + resourceType.slice(1);
        
        if (parts.length >= 6) {
          resourceId = parts[5];
          
          if (parts.length >= 7 && parts[6] === 'send') {
            functionName = 'send';
          }
        }
      }
    }
  }
  
  // Handle different HTTP methods
  switch (method) {
    case 'GET':
      if (resourceId) {
        // Get a specific resource
        return `// Get a specific ${resourceType.toLowerCase().slice(0, -1)}
Response<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().find(${grantId}, "${resourceId}");`;
      } else {
        // List resources
        if (Object.keys(params).length > 0) {
          return `// List ${resourceType.toLowerCase()} with query parameters
QueryParams queryParams = new QueryParams();
${Object.entries(params).map(([key, value]) => `queryParams.put("${key}", ${JSON.stringify(value)});`).join('\n')}

ListResponse<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().list(${grantId}, queryParams);`;
        } else {
          return `// List ${resourceType.toLowerCase()}
ListResponse<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().list(${grantId});`;
        }
      }
    
    case 'POST':
      if (functionName === 'send') {
        // Send a draft
        return `// Send a draft
Response<Message> response = nylas.${resourceType.toLowerCase()}().send(${grantId}, "${resourceId}");`;
      } else {
        // Create a resource
        return `// Create a new ${resourceType.toLowerCase().slice(0, -1)}
${resourceType.slice(0, -1)} new${resourceType.slice(0, -1)} = new ${resourceType.slice(0, -1)}.Builder()
    ${Object.entries(params).map(([key, value]) => {
      // Convert camelCase to method name (e.g., startTime -> startTime())
      const methodName = key.charAt(0).toLowerCase() + key.slice(1);
      return `    .${methodName}(${JSON.stringify(value)})`;
    }).join('\n')}
    .build();

Response<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().create(${grantId}, new${resourceType.slice(0, -1)});`;
      }
    
    case 'PUT':
      // Update a resource
      return `// Update a ${resourceType.toLowerCase().slice(0, -1)}
${resourceType.slice(0, -1)} updated${resourceType.slice(0, -1)} = new ${resourceType.slice(0, -1)}.Builder()
    ${Object.entries(params).map(([key, value]) => {
      // Convert camelCase to method name (e.g., startTime -> startTime())
      const methodName = key.charAt(0).toLowerCase() + key.slice(1);
      return `    .${methodName}(${JSON.stringify(value)})`;
    }).join('\n')}
    .build();

Response<${resourceType.slice(0, -1)}> response = nylas.${resourceType.toLowerCase()}().update(${grantId}, "${resourceId}", updated${resourceType.slice(0, -1)});`;
    
    case 'DELETE':
      // Delete a resource
      return `// Delete a ${resourceType.toLowerCase().slice(0, -1)}
Response<Void> response = nylas.${resourceType.toLowerCase()}().destroy(${grantId}, "${resourceId}");`;
    
    default:
      return `// No code generation available for this endpoint
String response = "Please refer to the Nylas API documentation for this endpoint.";`;
  }
}

/**
 * Generate Ruby code for the API endpoint
 */
function generateRubyCode(method: string, endpoint: string, params: Record<string, any>): string {
  const parts = endpoint.split('/');
  let resourceType = '';
  let functionName = '';
  let grantId = 'ENV["NYLAS_GRANT_ID"]';
  let resourceId = '';
  
  // Try to determine the resource type and function name
  if (parts.length >= 3) {
    if (parts[1] === 'v3' && parts[2] === 'grants') {
      if (parts.length >= 5) {
        resourceType = parts[4]; // like 'messages', 'events', etc.
        
        if (parts.length >= 6) {
          resourceId = parts[5];
          
          if (parts.length >= 7 && parts[6] === 'send') {
            functionName = 'send';
          }
        }
      }
    }
  }
  
  // Handle different HTTP methods
  switch (method) {
    case 'GET':
      if (resourceId) {
        // Get a specific resource
        return `# Get a specific ${resourceType.slice(0, -1)}
response, _ = nylas.${resourceType}.find(
  identifier: ${grantId}, 
  ${resourceType.slice(0, -1)}_id: "${resourceId}"${Object.keys(params).length > 0 ? `,
  query_params: {
    ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n    ')}
  }` : ''}
)`;
      } else {
        // List resources
        return `# List ${resourceType}
response, _ = nylas.${resourceType}.list(
  identifier: ${grantId}${Object.keys(params).length > 0 ? `,
  query_params: {
    ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n    ')}
  }` : ''}
)`;
      }
    
    case 'POST':
      if (functionName === 'send') {
        // Send a draft
        return `# Send a draft
response, _ = nylas.${resourceType}.send(
  identifier: ${grantId}, 
  ${resourceType.slice(0, -1)}_id: "${resourceId}"
)`;
      } else {
        // Create a resource
        return `# Create a new ${resourceType.slice(0, -1)}
response, _ = nylas.${resourceType}.create(
  identifier: ${grantId}, 
  request_body: {
    ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n    ')}
  }
)`;
      }
    
    case 'PUT':
      // Update a resource
      return `# Update a ${resourceType.slice(0, -1)}
response, _ = nylas.${resourceType}.update(
  identifier: ${grantId}, 
  ${resourceType.slice(0, -1)}_id: "${resourceId}", 
  request_body: {
    ${Object.entries(params).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',\n    ')}
  }
)`;
    
    case 'DELETE':
      // Delete a resource
      return `# Delete a ${resourceType.slice(0, -1)}
response, _ = nylas.${resourceType}.destroy(
  identifier: ${grantId}, 
  ${resourceType.slice(0, -1)}_id: "${resourceId}"
)`;
    
    default:
      return `# No code generation available for this endpoint
response = "Please refer to the Nylas API documentation for this endpoint."`;
  }
}

/**
 * Generate curl command for the API endpoint
 */
function generateCurlCode(method: string, endpoint: string, params: Record<string, any>): string {
  let baseUrl = "https://api.us.nylas.com";
  const fullUrl = `${baseUrl}${endpoint}`;
  
  // Handle different HTTP methods
  switch (method) {
    case 'GET':
      // Add query parameters if any
      if (Object.keys(params).length > 0) {
        const queryParams = Object.entries(params)
          .map(([key, value]) => `${key}=${encodeURIComponent(JSON.stringify(value))}`)
          .join('&');
        
        return `curl --request GET \\
  --url "${fullUrl}?${queryParams}" \\
  --header "Content-Type: application/json" \\
  --header "Authorization: Bearer $NYLAS_API_KEY"`;
      } else {
        return `curl --request GET \\
  --url "${fullUrl}" \\
  --header "Content-Type: application/json" \\
  --header "Authorization: Bearer $NYLAS_API_KEY"`;
      }
    
    case 'POST':
      // Include request body
      return `curl --request POST \\
  --url "${fullUrl}" \\
  --header "Content-Type: application/json" \\
  --header "Authorization: Bearer $NYLAS_API_KEY" \\
  --data '${JSON.stringify(params, null, 2)}'`;
    
    case 'PUT':
      // Include request body
      return `curl --request PUT \\
  --url "${fullUrl}" \\
  --header "Content-Type: application/json" \\
  --header "Authorization: Bearer $NYLAS_API_KEY" \\
  --data '${JSON.stringify(params, null, 2)}'`;
    
    case 'DELETE':
      return `curl --request DELETE \\
  --url "${fullUrl}" \\
  --header "Content-Type: application/json" \\
  --header "Authorization: Bearer $NYLAS_API_KEY"`;
    
    default:
      return `# No code generation available for this endpoint
# Please refer to the Nylas API documentation`;
  }
}
```
Page 2/2FirstPrevNextLast