TeamViewer MCP Server
TeamViewer MCP Server (no-DCR)
A Model Context Protocol (MCP) server that exposes the TeamViewer Web API as tools for AI assistants — specifically for MCP clients that don't support Dynamic Client Registration (RFC 7591), such as Microsoft Copilot Studio / Power Platform custom connectors.
The server is an OAuth 2.0 authorization server + resource server that brokers access to TeamViewer. It never hands MCP clients a real TeamViewer token: it issues its own opaque, audience-bound tokens, holds TeamViewer credentials encrypted server-side, and resolves a live TeamViewer token internally on every tool call.
MCP client (Copilot Studio)
↕ OAuth via /authorize, /token (this server)
MCP server (this repo)
↕ OAuth via account.teamviewer.com + webapi.teamviewer.com
TeamViewerTwo deployment variants
This project ships as two parallel repos, because the target MCP clients speak OAuth client registration differently:
Variant | Repo | Use for |
DCR |
| Clients that support Dynamic Client Registration (e.g. Claude.ai connectors) |
No-DCR (this repo) |
| Clients that don't (e.g. Microsoft Copilot Studio / Power Platform) |
This repo accepts any client_id (no registration step), but still strictly validates redirect_uri — either an exact match against MCP_ALLOWED_REDIRECT_URIS, or a trusted domain (and its subdomains) via MCP_ALLOWED_REDIRECT_HOSTS. At least one of the two must be set, or every /authorize request is rejected (fail closed).
Requirements
Node.js 22 or later
A TeamViewer account and an OAuth2 app registered in the TeamViewer Management Console (Integrations → Apps)
A publicly reachable HTTPS URL for local testing (TeamViewer's OAuth redirect requires one) — e.g. Tailscale Funnel or ngrok
Setup
1. Register a TeamViewer OAuth app
Go to login.teamviewer.com → Integrations → Apps and sign in.
Create an app and set its Callback URL to
{TEAMVIEWER_MCP_URL}/callback(the public URL this server will run at, plus/callback— see Step 3).Copy the Client ID and Client Secret.
2. Install and build
git clone https://github.com/NilsTv8/TV_ONE_MCP_Anthropic_noDCR.git
cd TV_ONE_MCP_Anthropic_noDCR
npm install
npm run build3. Configure environment variables
Variable | Required | Description |
| Yes | TV OAuth app client ID (from Step 1) |
| Yes | TV OAuth app client secret |
| No* | Comma-separated list of exact, trusted MCP-client callback URLs |
| No* | Comma-separated list of trusted domains — matches that host exactly or any subdomain of it (e.g. |
| Yes | Public base URL of this server (no trailing slash) |
| No | OAuth callback URL — defaults to |
| No | HTTP port (default |
* At least one of MCP_ALLOWED_REDIRECT_URIS / MCP_ALLOWED_REDIRECT_HOSTS must be set.
No encryption-key variable is needed — TeamViewer tokens are encrypted server-side with a key generated fresh in memory on every boot (see Security design below).
4. Run
TEAMVIEWER_CLIENT_ID=<id> \
TEAMVIEWER_CLIENT_SECRET=<secret> \
MCP_ALLOWED_REDIRECT_HOSTS=consent.azure-apim.net \
TEAMVIEWER_MCP_URL=https://<your-public-domain> \
PORT=3000 node dist/index.js5. Connect Copilot Studio (or another non-DCR client)
Create a custom connector with OAuth 2.0 "Generic" authentication:
Field | Value |
Authorization URL |
|
Token URL |
|
Refresh URL | same as Token URL |
Client ID / secret | from Step 1 |
Scope | see Available scopes below |
Power Platform generates its own redirect URL per connector after you save it (https://<region>.consent.azure-apim.net/redirect/<connector-id>) — that's exactly what MCP_ALLOWED_REDIRECT_HOSTS=consent.azure-apim.net is for; you don't need to copy the generated URL anywhere.
OAuth endpoints (auto-served)
Endpoint | Purpose |
| RFC 9728 protected resource metadata |
| RFC 8414 authorization server metadata |
| Starts the OAuth flow → redirects to TeamViewer |
| Exchanges an authorization code or refresh token |
| Revokes a token |
| TeamViewer redirects here after the user logs in |
(POST /register / Dynamic Client Registration is intentionally not offered in this variant — see the DCR repo instead.)
Available tools
27 action-based tools (each multi-action tool takes a single action parameter plus action-specific fields):
Group | Tools |
Account & Company |
|
Users & Access Management |
|
Contacts |
|
Devices & Device Groups |
|
Policies |
|
Monitoring |
|
Sessions & Remote Control |
|
Reports & Event Logs |
|
Tokens |
|
Each tool's description (visible via tools/list) documents its exact action values and parameters.
Available scopes
Requested during the OAuth flow; map to TeamViewer's own API permission scopes:
UserInfo.View · Computers.View · Computers.Edit · Computers.Delete · Groups.View · Groups.Create · Groups.Edit · Groups.Delete · Contacts.View · Contacts.Create · Contacts.Edit · Contacts.Delete · Partners.View · Sessions.ManualCreation
Docker
docker build -t teamviewer-mcp-nodcr .
docker run -p 3000:3000 \
-e TEAMVIEWER_CLIENT_ID=<id> \
-e TEAMVIEWER_CLIENT_SECRET=<secret> \
-e MCP_ALLOWED_REDIRECT_HOSTS=consent.azure-apim.net \
-e TEAMVIEWER_MCP_URL=https://<your-public-domain> \
teamviewer-mcp-nodcrThe image is a pinned, multi-stage, non-root build (compiles with dev dependencies in a build stage, ships only dist/ and production dependencies in the runtime stage) with a container HEALTHCHECK against /.well-known/oauth-authorization-server.
Production
Hosted on Azure App Service with this Docker image. Azure terminates TLS; the server always runs plain HTTP internally. Deploys automatically on every push to master.
Security design
No TeamViewer token pass-through — this server issues its own opaque, audience-bound tokens; TeamViewer access/refresh tokens are held server-side, AES-256-GCM encrypted, and only ever resolved internally right before a WebAPI call.
Refresh-token rotation with reuse detection — replaying a consumed refresh token revokes the whole session.
redirect_uriallow-list, not a rubber stamp — since anyclient_idis accepted, the allow-list (MCP_ALLOWED_REDIRECT_URIS/MCP_ALLOWED_REDIRECT_HOSTS) is the only check on where an authorization code can be sent; it's enforced so a mismatch gets a direct (non-redirecting) rejection, never a redirect to an unvalidated target.No raw upstream error text in tool results — a failed TeamViewer API call is logged in full server-side; only the HTTP status is surfaced to the calling tool/LLM.
See CLAUDE.md in this repo for full architectural detail, local dev setup, and environment specifics.
License
MIT