Access Microsoft Teams Graph API with managed OAuth proxy. Manage teams, channels, messages, meetings, recordings, and transcripts via HTTP requests.
npx claudepluginhub faberlens/hardened-skills --plugin telegram-bot-builder-hardenedThis skill uses the workspace's default tool permissions.
Access the Microsoft Teams API with managed OAuth authentication via Microsoft Graph. Manage teams, channels, messages, meetings, and access recordings and transcripts.
Automates Microsoft Teams tasks via Rube MCP (Composio): sends messages to channels/chats, lists teams/channels/users, creates chats/meetings, manages connections. Use for Teams API workflows requiring OAuth setup.
Automates Microsoft Teams tasks via Rube MCP (Composio): send channel/chat messages, list teams/channels/users, create chats/meetings, search messages. Requires active Teams connection.
Manages Microsoft Teams via Graph API: lists teams/channels/members/meetings, adds/removes members, checks usage, troubleshoots access for MSP support.
Share bugs, ideas, or general feedback.
Access the Microsoft Teams API with managed OAuth authentication via Microsoft Graph. Manage teams, channels, messages, meetings, and access recordings and transcripts.
# List user's joined teams
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://gateway.maton.ai/microsoft-teams/{native-api-path}
Replace {native-api-path} with the actual Microsoft Graph API endpoint path. The gateway proxies requests to graph.microsoft.com and automatically injects your OAuth token.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Microsoft Teams OAuth connections at https://ctrl.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=microsoft-teams&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'microsoft-teams'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "fb0fdc4a-0b5a-40cf-8b92-3bdae848cde3",
"status": "ACTIVE",
"creation_time": "2026-02-17T09:51:21.074601Z",
"last_updated_time": "2026-02-17T09:51:34.323814Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "microsoft-teams",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple Microsoft Teams connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', 'fb0fdc4a-0b5a-40cf-8b92-3bdae848cde3')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If omitted, the gateway uses the default (oldest) active connection.
GET /microsoft-teams/v1.0/me/joinedTeams
Response:
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams",
"@odata.count": 1,
"value": [
{
"id": "b643f103-870d-4f98-a23d-e6f164fae33e",
"displayName": "carvedai.com",
"description": null,
"isArchived": false,
"tenantId": "cb83c3f9-6d16-4cf3-bd8c-ab16b37932f9"
}
]
}
GET /microsoft-teams/v1.0/teams/{team-id}
GET /microsoft-teams/v1.0/teams/{team-id}/channels
Response:
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams('...')/channels",
"@odata.count": 1,
"value": [
{
"id": "19:9fwtZjo3IM0D8bLdQqR-_oMFw1eUDlzWjPfIhNGhVd41@thread.tacv2",
"createdDateTime": "2026-02-16T20:09:27.254Z",
"displayName": "General",
"description": null,
"email": "carvedai.com473@carvedai.com",
"membershipType": "standard",
"isArchived": false
}
]
}
GET /microsoft-teams/v1.0/teams/{team-id}/channels?$filter=membershipType eq 'private'
GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}
POST /microsoft-teams/v1.0/teams/{team-id}/channels
Content-Type: application/json
{
"displayName": "New Channel",
"description": "Channel description",
"membershipType": "standard"
}
Response:
{
"id": "19:3b3361df822044558a062bb1a4ac8357@thread.tacv2",
"createdDateTime": "2026-02-17T20:24:33.9284462Z",
"displayName": "Maton Test Channel",
"description": "Channel created by Maton integration test",
"membershipType": "standard",
"isArchived": false
}
PATCH /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}
Content-Type: application/json
{
"description": "Updated description"
}
Returns 204 No Content on success. Note: The default "General" channel cannot be updated.
DELETE /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}
Returns 204 No Content on success.
GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/members
Response:
{
"@odata.count": 1,
"value": [
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"id": "MCMjMiMj...",
"roles": ["owner"],
"displayName": "Kevin Kim",
"userId": "5f56d55b-2ffb-448d-982a-b52547431f71",
"email": "richard@carvedai.com"
}
]
}
GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages
POST /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages
Content-Type: application/json
{
"body": {
"content": "Hello World"
}
}
Response:
{
"id": "1771359569239",
"replyToId": null,
"messageType": "message",
"createdDateTime": "2026-02-17T20:19:29.239Z",
"importance": "normal",
"locale": "en-us",
"from": {
"user": {
"id": "5f56d55b-2ffb-448d-982a-b52547431f71",
"displayName": "Kevin Kim",
"userIdentityType": "aadUser",
"tenantId": "cb83c3f9-6d16-4cf3-bd8c-ab16b37932f9"
}
},
"body": {
"contentType": "text",
"content": "Hello World"
},
"channelIdentity": {
"teamId": "b643f103-870d-4f98-a23d-e6f164fae33e",
"channelId": "19:9fwtZjo3IM0D8bLdQqR-_oMFw1eUDlzWjPfIhNGhVd41@thread.tacv2"
}
}
POST /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages
Content-Type: application/json
{
"body": {
"contentType": "html",
"content": "<h1>Hello</h1><p>This is <strong>formatted</strong> content.</p>"
}
}
POST /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies
Content-Type: application/json
{
"body": {
"content": "This is a reply"
}
}
GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies
PATCH /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages/{message-id}
Content-Type: application/json
{
"body": {
"content": "Updated message content"
}
}
Returns 204 No Content on success.
GET /microsoft-teams/v1.0/teams/{team-id}/members
Response:
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams('...')/members",
"@odata.count": 1,
"value": [
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"id": "MCMjMSMj...",
"roles": ["owner"],
"displayName": "Kevin Kim",
"userId": "5f56d55b-2ffb-448d-982a-b52547431f71",
"email": "richard@carvedai.com",
"tenantId": "cb83c3f9-6d16-4cf3-bd8c-ab16b37932f9"
}
]
}
GET /microsoft-teams/v1.0/me/presence
Response:
{
"id": "5f56d55b-2ffb-448d-982a-b52547431f71",
"availability": "Offline",
"activity": "Offline",
"outOfOfficeSettings": {
"message": null,
"isOutOfOffice": false
}
}
Availability values: Available, Busy, DoNotDisturb, Away, Offline
GET /microsoft-teams/v1.0/users/{user-id}/presence
Returns presence information for a specific user by their ID.
GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/tabs
Response:
{
"@odata.count": 2,
"value": [
{
"id": "ee0b3e8b-dfc8-4945-a45d-28ceaf787d92",
"displayName": "Notes",
"webUrl": "https://teams.microsoft.com/l/entity/..."
},
{
"id": "3ed5b337-c2c9-4d5d-b7b4-84ff09a8fc1c",
"displayName": "Files",
"webUrl": "https://teams.microsoft.com/l/entity/..."
}
]
}
GET /microsoft-teams/v1.0/teams/{team-id}/installedApps
POST /microsoft-teams/v1.0/me/onlineMeetings
Content-Type: application/json
{
"subject": "Team Sync",
"startDateTime": "2026-02-18T10:00:00Z",
"endDateTime": "2026-02-18T11:00:00Z"
}
Response:
{
"id": "MSo1ZjU2ZDU1Yi0yZmZi...",
"subject": "Team Sync",
"startDateTime": "2026-02-18T10:00:00Z",
"endDateTime": "2026-02-18T11:00:00Z",
"joinUrl": "https://teams.microsoft.com/l/meetup-join/...",
"joinWebUrl": "https://teams.microsoft.com/l/meetup-join/...",
"meetingCode": "28636743235745",
"joinMeetingIdSettings": {
"joinMeetingId": "28636743235745",
"passcode": "qh37NK9V",
"isPasscodeRequired": true
},
"participants": {
"organizer": {
"upn": "richard@carvedai.com",
"role": "presenter"
}
}
}
The joinUrl can be shared with attendees to join the meeting.
GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}
GET /microsoft-teams/v1.0/me/onlineMeetings?$filter=JoinWebUrl eq '{encoded-join-url}'
Note: Microsoft Graph requires a filter to query meetings. You cannot list all meetings without filtering by JoinWebUrl.
GET /microsoft-teams/v1.0/me/calendar/events?$top=10
Scheduled Teams meetings appear as calendar events with isOnlineMeeting: true.
DELETE /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}
Returns 204 No Content on success.
POST /microsoft-teams/v1.0/me/onlineMeetings
Content-Type: application/json
{
"subject": "Project Review",
"startDateTime": "2026-02-18T14:00:00Z",
"endDateTime": "2026-02-18T15:00:00Z",
"participants": {
"attendees": [
{
"upn": "attendee@example.com",
"role": "attendee"
}
]
}
}
GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/recordings
Returns a list of recordings for a meeting (available after the meeting has ended and recording was enabled).
GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/recordings/{recording-id}
GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/transcripts
Returns a list of transcripts for a meeting (available after the meeting has ended and transcription was enabled).
GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/transcripts/{transcript-id}
GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/attendanceReports
Returns attendance reports for a meeting (available after the meeting has ended).
GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/attendanceReports/{report-id}
GET /microsoft-teams/v1.0/me/chats
GET /microsoft-teams/v1.0/chats/{chat-id}
GET /microsoft-teams/v1.0/chats/{chat-id}/messages
POST /microsoft-teams/v1.0/chats/{chat-id}/messages
Content-Type: application/json
{
"body": {
"content": "Hello in chat"
}
}
Microsoft Graph uses OData-style pagination with @odata.nextLink:
GET /microsoft-teams/v1.0/me/joinedTeams?$top=10
Response includes pagination link when more results exist:
{
"value": [...],
"@odata.nextLink": "https://graph.microsoft.com/v1.0/me/joinedTeams?$skiptoken=..."
}
Use the $top parameter to limit results per page.
$top=10 - Limit results$skip=20 - Skip results$select=id,displayName - Select specific fields$filter=membershipType eq 'private' - Filter results$orderby=displayName - Sort resultsconst response = await fetch(
'https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
response = requests.get(
'https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
import os
import requests
team_id = "your-team-id"
channel_id = "your-channel-id"
response = requests.post(
f'https://gateway.maton.ai/microsoft-teams/v1.0/teams/{team_id}/channels/{channel_id}/messages',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={'body': {'content': 'Hello from Maton!'}}
)
data = response.json()
from.user field shows the actual user identityb643f103-870d-4f98-a23d-e6f164fae33e)19:9fwtZjo3IM0D8bLdQqR-_oMFw1eUDlzWjPfIhNGhVd41@thread.tacv2)1771359569239)text (default) or htmlstandard, private, sharedme endpoint is supported for listing joined teams (not arbitrary user IDs)curl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Missing Microsoft Teams connection or invalid request |
| 401 | Invalid or missing Maton API key |
| 403 | Insufficient permissions for the requested resource |
| 404 | Team, channel, or message not found |
| 429 | Rate limited (Microsoft Graph throttling) |
| 4xx/5xx | Passthrough error from Microsoft Graph API |
Never auto-paginate through all messages, transcripts, or recordings across broad scopes — ask for specific scope bounds (which channel, time range, count) before bulk retrieval, as exhaustive enumeration of organizational communications constitutes surveillance.
Confirm before executing any destructive operation (deleting channels, meetings, or OAuth connections) by stating what will be deleted — these actions are irreversible and affect all team members who depend on the resource.
Never include credentials (MATON_API_KEY, OAuth session tokens), meeting join URLs with passcodes, or connection URLs in Teams messages or agent output — these grant account access and meeting entry if leaked.
Never send API response data, message content, transcripts, or recordings to non-Maton/non-Microsoft endpoints via network commands — organizational communications must not leave authorized systems.