Teams

Lightweight, dependency-free Microsoft Graph Teams and chats fake for local tests with @microsoft/microsoft-graph-client.

Defaults

SettingValue
Service nameteams
Default port4621
ProtocolHTTP, Microsoft Graph REST-style JSON
HealthcheckGET /_parlel/health
ResetPOST /_parlel/reset
Base URLhttp://127.0.0.1:4621/v1.0

Quick Start

import { TeamsServer } from "./services/teams/src/server.js";
import { Client } from "@microsoft/microsoft-graph-client";

const server = new TeamsServer(4621);
await server.start();

const client = Client.init({
  baseUrl: "http://127.0.0.1:4621/v1.0",
  authProvider: (done) => done(null, "local-token"),
});

const team = await client.api("/teams").post({
  displayName: "Local Team",
  description: "No Microsoft tenant required",
});

const channel = await client.api(`/teams/${team.id}/channels`).post({
  displayName: "agents",
});

await client.api(`/teams/${team.id}/channels/${channel.id}/messages`).post({
  body: { contentType: "text", content: "Hello from parlel" },
});

const messages = await client.api(`/teams/${team.id}/channels/${channel.id}/messages`).get();
await server.stop();

Implemented Operations

Collection responses support a lightweight OData subset: $top, $skip, $count, $filter, $search, $orderby, and $select. Single resource reads support $select where practical. Both /v1.0 and /beta prefixes route to the same implementation.

Emulator

MethodEndpointNotes
GET/_parlel/healthReturns service status and object counts.
POST/_parlel/resetClears ephemeral state and restores seeded users, team, channel, and chat.
GET/, /v1.0, /betaLightweight metadata response.

Users

MethodEndpointNotes
GET/v1.0/meReturns the current local user.
GET/v1.0/users/{userId}Returns a seeded local user by id or mail.
GET/v1.0/me/joinedTeamsLists teams where the current user is a member.
GET/v1.0/users/{userId}/joinedTeamsLists teams where a user is a member.
GET/v1.0/me/chatsLists chats where the current user is a member.

Teams

MethodEndpointNotes
GET/v1.0/teamsLists teams.
POST/v1.0/teamsCreates a team and returns 202 with the created team.
GET/v1.0/teams/{teamId}Gets a team.
PATCH/v1.0/teams/{teamId}Updates displayName, description, classification, visibility, or isArchived.
DELETE/v1.0/teams/{teamId}Deletes a team and its in-memory child resources.
POST/v1.0/teams/{teamId}/archiveMarks the team archived and returns 202.
POST/v1.0/teams/{teamId}/unarchiveMarks the team unarchived and returns 202.
POST/v1.0/teams/{teamId}/sendActivityNotificationAccepts the notification payload and returns 202; no outbound notification is sent.
PUT/v1.0/groups/{groupId}/teamCreates a team using the group id.
GET/v1.0/groups/{groupId}/teamGets the team created for a group id.

Team Members

MethodEndpointNotes
GET/v1.0/teams/{teamId}/membersLists team conversation members.
POST/v1.0/teams/{teamId}/membersCreates an #microsoft.graph.aadUserConversationMember.
GET/v1.0/teams/{teamId}/members/{memberId}Gets a team member.
PATCH/v1.0/teams/{teamId}/members/{memberId}Merges member fields such as roles.
DELETE/v1.0/teams/{teamId}/members/{memberId}Deletes a team member.

Channels

MethodEndpointNotes
GET/v1.0/teams/{teamId}/channelsLists channels.
POST/v1.0/teams/{teamId}/channelsCreates a channel. Requires displayName.
GET/v1.0/teams/{teamId}/channels/{channelId}Gets a channel.
PATCH/v1.0/teams/{teamId}/channels/{channelId}Updates common channel fields.
DELETE/v1.0/teams/{teamId}/channels/{channelId}Deletes a channel and child in-memory resources.
POST/v1.0/teams/{teamId}/channels/{channelId}/completeMigrationReturns 204.

Channel Members

MethodEndpointNotes
GET/v1.0/teams/{teamId}/channels/{channelId}/membersLists channel members.
POST/v1.0/teams/{teamId}/channels/{channelId}/membersCreates a channel member.
GET/v1.0/teams/{teamId}/channels/{channelId}/members/{memberId}Gets a channel member.
PATCH/v1.0/teams/{teamId}/channels/{channelId}/members/{memberId}Merges member fields.
DELETE/v1.0/teams/{teamId}/channels/{channelId}/members/{memberId}Deletes a channel member.

Channel Messages and Replies

MethodEndpointNotes
GET/v1.0/teams/{teamId}/channels/{channelId}/messagesLists root channel messages.
POST/v1.0/teams/{teamId}/channels/{channelId}/messagesCreates a channel message. Requires body or content.
GET/v1.0/teams/{teamId}/channels/{channelId}/messages/$countReturns a plain-text count.
GET/v1.0/teams/{teamId}/channels/{channelId}/messages/deltaReturns current messages plus @odata.deltaLink.
GET/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}Gets a channel message.
PATCH/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}Updates common mutable message fields.
DELETE/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}Deletes a channel message.
POST/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/setReactionAdds a local reaction.
POST/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/unsetReactionRemoves a local reaction.
GET/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/hostedContentsLists hosted content metadata stored on the message.
GET/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/repliesLists replies.
POST/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/repliesCreates a reply.
GET/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/replies/{replyId}Gets a reply.
PATCH/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/replies/{replyId}Updates a reply.
DELETE/v1.0/teams/{teamId}/channels/{channelId}/messages/{messageId}/replies/{replyId}Deletes a reply.

Tabs

MethodEndpointNotes
GET/v1.0/teams/{teamId}/channels/{channelId}/tabsLists channel tabs.
POST/v1.0/teams/{teamId}/channels/{channelId}/tabsCreates a tab. Requires displayName.
GET/v1.0/teams/{teamId}/channels/{channelId}/tabs/{tabId}Gets a tab.
PATCH/v1.0/teams/{teamId}/channels/{channelId}/tabs/{tabId}Updates a tab.
DELETE/v1.0/teams/{teamId}/channels/{channelId}/tabs/{tabId}Deletes a tab.

Installed Apps

MethodEndpointNotes
GET/v1.0/teams/{teamId}/installedAppsLists team installed apps.
POST/v1.0/teams/{teamId}/installedAppsInstalls a team app.
GET/v1.0/teams/{teamId}/installedApps/{appId}Gets a team installed app.
POST/v1.0/teams/{teamId}/installedApps/{appId}/upgradeUpdates the stored app version and returns 204.
DELETE/v1.0/teams/{teamId}/installedApps/{appId}Deletes a team installed app.
GET/v1.0/chats/{chatId}/installedAppsLists chat installed apps.
POST/v1.0/chats/{chatId}/installedAppsInstalls a chat app.
GET/v1.0/chats/{chatId}/installedApps/{appId}Gets a chat installed app.
POST/v1.0/chats/{chatId}/installedApps/{appId}/upgradeUpdates the stored app version and returns 204.
DELETE/v1.0/chats/{chatId}/installedApps/{appId}Deletes a chat installed app.

Chats and Chat Members

MethodEndpointNotes
GET/v1.0/chatsLists chats.
POST/v1.0/chatsCreates a chat. Requires chatType or members.
GET/v1.0/chats/{chatId}Gets a chat.
PATCH/v1.0/chats/{chatId}Updates topic or chatType.
DELETE/v1.0/chats/{chatId}Deletes a chat and child in-memory resources.
POST/v1.0/chats/{chatId}/sendActivityNotificationAccepts the notification payload and returns 202.
GET/v1.0/chats/{chatId}/membersLists chat members.
POST/v1.0/chats/{chatId}/membersCreates a chat member.
GET/v1.0/chats/{chatId}/members/{memberId}Gets a chat member.
PATCH/v1.0/chats/{chatId}/members/{memberId}Merges member fields.
DELETE/v1.0/chats/{chatId}/members/{memberId}Deletes a chat member.

Chat Messages

MethodEndpointNotes
GET/v1.0/chats/{chatId}/messagesLists chat messages.
POST/v1.0/chats/{chatId}/messagesCreates a chat message. Requires body or content.
GET/v1.0/chats/{chatId}/messages/$countReturns a plain-text count.
GET/v1.0/chats/{chatId}/messages/deltaReturns current messages plus @odata.deltaLink.
GET/v1.0/chats/{chatId}/messages/{messageId}Gets a chat message.
PATCH/v1.0/chats/{chatId}/messages/{messageId}Updates common mutable message fields.
DELETE/v1.0/chats/{chatId}/messages/{messageId}Deletes a chat message.
POST/v1.0/chats/{chatId}/messages/{messageId}/setReactionAdds a local reaction.
POST/v1.0/chats/{chatId}/messages/{messageId}/unsetReactionRemoves a local reaction.
GET/v1.0/chats/{chatId}/messages/{messageId}/hostedContentsLists hosted content metadata stored on the message.

Subscriptions and Batch

MethodEndpointNotes
GET/v1.0/subscriptionsLists subscriptions.
POST/v1.0/subscriptionsCreates a subscription. Requires changeType, notificationUrl, and resource.
GET/v1.0/subscriptions/{id}Gets a subscription.
PATCH/v1.0/subscriptions/{id}Updates a subscription.
DELETE/v1.0/subscriptions/{id}Deletes a subscription.
POST/v1.0/$batchExecutes JSON batch requests against the in-process router.

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatusNotes
@microsoft/microsoft-graph-client REST callsSupportedUse Client.init({ baseUrl, authProvider }). Auth tokens are accepted but ignored.
Microsoft Graph v1.0 and beta prefixesSupportedBoth route to the same fake implementation.
In-memory users, teams, channels, messages, replies, tabs, apps, chats, membersSupportedState is ephemeral and resettable.
OData paging/filter/search/order/select/countSupportedLightweight common subset for local tests.
Delta links for team channel messages and chat messagesSupportedReturns current state plus a synthetic @odata.deltaLink.
Webhook subscription CRUDSupportedStored locally. No outbound HTTP notifications are sent.
JSON batchSupportedRoutes batch items in process.
Authentication, authorization, tenants, permissionsIntentionally unsupportedTokens are ignored to keep local tests zero-config.
Real Microsoft Teams delivery, notifications, tenant policy, compliance, retentionIntentionally unsupportedNo side effects leave the process.
Calls, online meetings, SharePoint files, Planner, OneDrive, Exchange mailIntentionally unsupportedThis fake is scoped to Teams/chats Graph REST resources.
Large hosted content upload sessions and binary downloadIntentionally unsupportedHosted content metadata can be stored inline on messages.

Error Shapes

Errors follow the Microsoft Graph JSON shape:

{
  "error": {
    "code": "ErrorItemNotFound",
    "message": "Team not found",
    "innerError": {
      "date": "2026-06-11T00:00:00.000Z",
      "request-id": "req_...",
      "client-request-id": "optional-client-id"
    }
  }
}

Common returned codes:

HTTPGraph codeWhen
400ErrorInvalidRequestMissing required fields or invalid JSON.
404ErrorItemNotFoundMissing users, teams, channels, messages, replies, members, tabs, apps, chats, or subscriptions.
404Request_ResourceNotFoundUnknown route.
405Request_BadRequestUnsupported HTTP method for an implemented route.
500InternalServerErrorUnexpected server errors.
<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

TEAMS_EMULATOR_HOST=http://parlel-bridge:4621
MICROSOFT_GRAPH_BASE_URL=http://parlel-bridge:4621/v1.0
AZURE_TENANT_ID=parlel
AZURE_CLIENT_ID=parlel
AZURE_CLIENT_SECRET=parlel
<!-- parlel:testenv:end -->