1. Astravue MCP Server
Astravue docs
  • Astravue API & MCP
  • Auth
    • Get Access and Refresh Token
      POST
    • Refresh Access Token
      POST
  • Personal Tasks
    • Get task by ID
      GET
    • Update a task
      PUT
    • Delete a task
      DELETE
    • Get all tasks
      GET
    • Create a task
      POST
  • Spaces
    • Get space by ID
      GET
    • Update a space
      PUT
    • Delete a space
      DELETE
    • Get all spaces
      GET
    • Create a new space
      POST
  • Projects
    • Get project details by ID
      GET
    • Update a project
      PUT
    • Delete a project
      DELETE
    • Get all projects in a space
      GET
    • Create a new project
      POST
  • Project Tasks
    • Get a project task by ID
      GET
    • Update a project task
      PUT
    • Delete a project task
      DELETE
    • Get all tasks in a project
      GET
    • Create a project task
      POST
  • Task Timer
    • Get active timers for a user
    • Update a timer
    • Delete a timer entry
    • Stop timer for a task
    • Start timer for a personal task
    • Add a time range entry for a personal task
    • Add manual time entry for a personal task
    • Start timer for a project task
    • Add range timer for a project task
    • Add manual time entry for a project task
    • Get timers for a user in a task
    • Get global timesheet report
    • Get project timesheet
    • Get project timesheet summary
  • Task Comments
    • Get comments for a task
  • Project Subtasks
    • Get all subtasks for a project task
  • Personal Subtasks
    • Get all subtasks for a personal task
  • Tasks Checklist
    • Get all checklists for a subtask
    • Get all checklists for a parent task
  • Astravue MCP Server
    • Overview
    • Get started
    • Supported tools
    • Authentication & Security
    • Integrating your own MCP client
  • Schemas
    • Schemas
      • ApiError
      • TimerData
      • NotificationReadResponseDto
      • FieldError
      • TimerUpdateRequest
      • NotificationDto
      • ApiSuccessResponseListTaskCheckListDto
      • TimeTrackerDto
      • TaskCommentDto
      • TaskCheckListDto
      • TaskListResponse
      • TaskUpdateRequest
      • NotificationDeleteRequestDto
      • ApiSuccessResponseTaskDto
      • TimerRequest
      • NotificationDeleteResponseDto
      • ApiSuccessResponseListTaskCommentDto
      • CustomFieldOptionDto
      • RangeTimerRequest
      • ApiSuccessResponseSubtaskListResponse
      • OrgRoleDto
      • ManualTimerRequest
      • SubtaskListResponse
      • TaskCustomFieldDto
      • TaskTimerResponseDto
      • TaskDependencyDto
      • TaskDto
      • TaskFieldValue
      • TaskPriorityDto
      • TaskResponseDto
      • TaskStatusDto
      • TaskTagDto
      • UserDisplayDto
      • SpaceUpdateRequest
      • ApiSuccessResponseSpaceDto
      • SpaceDto
      • SpaceMemberDto
      • SpaceRoleDto
      • ProjectUpdateRequest
      • AccountLabelDto
      • ApiSuccessResponseProjectDto
      • ContactDto
      • ContactProperties
      • ContactTagDto
      • ProjectDto
      • ProjectHealthDto
      • ProjectMemberDto
      • ProjectPriorityDto
      • ProjectRoleDto
      • ProjectStatusDto
      • ProjectTagDto
      • ProjectTaskUpdateRequest
      • AppDto
      • ResponseFormat
      • OrgMemberDto
      • UserPreference
      • UserPreferenceProperties
      • PasswordUpdateDto
      • UserDetailDto
      • MemberPreferenceDto
      • WidgetProperties
      • TimeMapDto
      • TaskStatusTemplateDto
      • DefaultProjectTaskStatusesTemplateDto
      • EmailContent
      • AttachmentDto
      • ReminderModeDto
      • TaskReminderDto
      • DailyRecurrenceSettings
      • DaysAfterRecurrenceSettings
      • FieldsToInclude
      • MonthlyRecurrenceSettings
      • TaskRecurrenceDto
      • WeeklyRecurrenceSettings
      • YearlyRecurrenceSettings
      • TaskListDto
      • OrganizationDto
      • Address
      • BillingAndAccountInfo
      • Filter
      • FilterList
      • FilterViewDto
      • CalendarEvent
      • EventReminder
      • ContactNotesDto
      • ColumnPreferenceDto
      • ColumnPreferenceProperties
      • AccountDto
      • AccountTagDto
      • ContactLabelDto
      • TaskCreateRequest
      • SpaceCreateRequest
      • ProjectCreateRequest
      • ProjectTaskCreateRequest
      • FileUploadDto
      • GlobalTaskStatusesTemplateDto
      • PasswordResetDto
      • UserDto
      • InviteUserDto
      • UserActivity
      • UserActivityKey
      • ApiSuccessResponseTaskListResponse
      • ApiSuccessResponseProjectListResponse
      • ApiSuccessResponseListSpaceDto
      • ProjectListResponse
      • ApiSuccessResponseObject
      • BackupUserActivity
    • TimesheetReportResponse
    • ProjectTimesheetResponse
  1. Astravue MCP Server

Integrating your own MCP client

Learn how to connect your own AI tool or application to Astravue MCP using OAuth 2.0.

Overview#

Astravue provides a hosted MCP server that lets any MCP-compatible client interact with your workspace.
If you are building your own AI tool or integration, this guide walks you through the OAuth 2.0 Authorization Code flow with PKCE used by Astravue MCP.
TransportURLNotes
Streamable HTTPhttps://api.astravue.com/mcpOnly supported transport
Key requirements
OAuth 2.0 Authorization Code flow with PKCE
Streamable HTTP transport support
Token refresh handling
Secure credential storage

Prerequisites#

INFO
This guide uses TypeScript / JavaScript examples.
The OAuth 2.0 flow, PKCE implementation, and MCP protocol are language-agnostic — the same concepts apply in any language.
Required libraries (TypeScript / JavaScript)
Python
Go
Java / Spring
Rust
C# / .NET

Key references#

Model Context Protocol Specification
RFC 6749 — OAuth 2.0 Authorization Framework
RFC 7636 — PKCE
RFC 8414 — Authorization Server Metadata
RFC 9728 — OAuth 2.0 Protected Resource Metadata

Step 1 — OAuth Discovery#

Before connecting, discover Astravue’s OAuth configuration using the standard discovery process.
1.
Fetch Protected Resource Metadata (RFC 9728)
2.
Fetch Authorization Server Metadata (RFC 8414)
type OAuthMetadata = {
  issuer: string
  authorization_endpoint: string
  token_endpoint: string
  registration_endpoint?: string
}

async function discoverOAuthMetadata(mcpServerUrl: string): Promise<OAuthMetadata> {

  const url = new URL(mcpServerUrl)

  const protectedResourceUrl = new URL(
    "/.well-known/oauth-protected-resource",
    url
  )

  const protectedResourceResponse = await fetch(protectedResourceUrl.toString())

  if (!protectedResourceResponse.ok) {
    throw new Error("Failed to fetch protected resource metadata")
  }

  const protectedResource = await protectedResourceResponse.json()

  const authServerUrl = protectedResource.authorization_servers[0]

  const metadataUrl = new URL(
    "/.well-known/oauth-authorization-server",
    authServerUrl
  )

  const metadataResponse = await fetch(metadataUrl.toString())

  if (!metadataResponse.ok) {
    throw new Error("Failed to fetch authorization server metadata")
  }

  return metadataResponse.json()
}
Astravue discovery endpoints:
https://api.astravue.com/.well-known/oauth-protected-resource
https://api.astravue.com/.well-known/oauth-authorization-server

Step 2 — Generate PKCE Parameters#

PKCE protects the OAuth authorization code flow.
import { randomBytes, createHash } from "crypto"

function base64URLEncode(buffer: Buffer): string {
  return buffer
    .toString("base64")
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=/g, "")
}

function generateCodeVerifier(): string {
  return base64URLEncode(randomBytes(32))
}

function generateCodeChallenge(verifier: string): string {

  const hash = createHash("sha256")
    .update(verifier)
    .digest()

  return base64URLEncode(hash)
}

const codeVerifier = generateCodeVerifier()

const codeChallenge = generateCodeChallenge(codeVerifier)
WARNING
Never send the codeVerifier until the token exchange step.
Store it securely in memory or encrypted session storage.

Step 3 — Dynamic Client Registration#

Astravue MCP supports RFC 7591 dynamic client registration.
async function registerClient(metadata: OAuthMetadata, redirectUri: string) {

  const registration = {
    client_name: "Your MCP Client",
    redirect_uris: [redirectUri]
  }

  const response = await fetch(metadata.registration_endpoint!, {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(registration)
  })

  if (!response.ok) {
    throw new Error("Client registration failed")
  }

  return response.json()
}

Step 4 — Build Authorization URL#

function buildAuthorizationUrl(
  metadata: OAuthMetadata,
  clientId: string,
  redirectUri: string,
  codeChallenge: string,
  state: string
) {

  const params = new URLSearchParams({
    response_type: "code",
    client_id: clientId,
    redirect_uri: redirectUri,
    scope: "openid profile email",
    state: state,
    code_challenge: codeChallenge,
    code_challenge_method: "S256",
    resource: mcpServerUrl
  })

  return `${metadata.authorization_endpoint}?${params}`
}
Redirect your user to this URL to begin authentication.

Step 5 — Handle OAuth Callback#

function parseCallback(url: string) {

  const params = new URLSearchParams(new URL(url).search)

  return {
    code: params.get("code"),
    state: params.get("state"),
    error: params.get("error")
  }
}
Always validate the state parameter before continuing.

Step 6 — Exchange Authorization Code#

async function exchangeCodeForTokens(
  code: string,
  codeVerifier: string,
  metadata: OAuthMetadata,
  clientId: string,
  redirectUri: string
) {

  const params = new URLSearchParams({
    grant_type: "authorization_code",
    code,
    client_id: clientId,
    redirect_uri: redirectUri,
    code_verifier: codeVerifier,
    resource: "https://api.astravue.com/mcp"
  })

  const response = await fetch(metadata.token_endpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded"
    },
    body: params.toString()
  })

  if (!response.ok) {
    throw new Error("Token exchange failed")
  }

  return response.json()
}
The resource parameter ensures the access token is issued for the Astravue MCP server (sets the aud claim).
WARNING
Token storage guidelines
Web apps — store tokens server-side only
Desktop apps — use OS keychain
Mobile apps — use secure keystore APIs
Always encrypt tokens at rest

Step 7 — Connect to Astravue MCP#

Astravue MCP uses Streamable HTTP transport only.
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"

async function createMcpClient(accessToken: string): Promise<Client> {

  const client = new Client(
    { name: "your-mcp-client", version: "1.0.0" },
    { capabilities: { roots: {}, sampling: {} } }
  )

  const transport = new StreamableHTTPClientTransport(
    new URL("https://api.astravue.com/mcp"),
    {
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "User-Agent": "YourApp-MCP-Client/1.0"
      }
    }
  )

  await client.connect(transport)

  return client
}

Step 8 — Handle Token Refresh#

Access tokens expire after 30 minutes.
async function refreshAccessToken(
  refreshToken: string,
  metadata: OAuthMetadata,
  clientId: string
) {

  const params = new URLSearchParams({
    grant_type: "refresh_token",
    refresh_token: refreshToken,
    client_id: clientId
  })

  const response = await fetch(metadata.token_endpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded"
    },
    body: params.toString()
  })

  if (!response.ok) {
    throw new Error("Token refresh failed")
  }

  return response.json()
}
INFO
Astravue uses refresh token rotation.
Each refresh request returns a new refresh token and invalidates the previous one.

Token Reference#

TokenLifetimePurpose
Access token30 minAuthorizes MCP tool calls
Refresh token24 hoursIssues new access tokens

Security Checklist#

Always use HTTPS
Validate OAuth state parameter
Encrypt stored tokens
Always use PKCE S256
Refresh tokens before expiry
Handle invalid_grant gracefully
Log OAuth operations for auditing

Troubleshooting#

OAuth discovery fails
Invalid state parameter
invalid audience
Token refresh fails

Additional resources#

Model Context Protocol Specification
MCP TypeScript SDK
RFC 7636 — PKCE
RFC 9728— OAuth 2.0 Protected Resource Metadata
Previous
Authentication & Security
Next
ApiError
Built with