Self-Hosted Teamso MCP
Run the Teamso MCP server from the open-source npm package (@teamso/teamso-mcp) with npx on your machine or on your own server. Nothing sits between your client and the Teamso API.
Quick start
Requires Node.js 20 or later. Add this to your MCP client's configuration:
{
"mcpServers": {
"teamso": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@teamso/[email protected]"
],
"env": {
"TEAMSO_ACCESS_TOKEN": "tms_pat_..."
}
}
}
}The version is pinned so npx does not run an old cached build.
Setup
The package runs over stdio and works with any MCP client that supports stdio.
Cursor
Open ~/.cursor/mcp.json with Cmd+Shift+P → Open MCP settings and add:
{
"mcpServers": {
"teamso": {
"command": "npx",
"args": [
"-y",
"@teamso/[email protected]"
],
"env": {
"TEAMSO_ACCESS_TOKEN": "tms_pat_..."
}
}
}
}Claude Code
Add it, passing the token as an environment variable:
claude mcp add teamso --env TEAMSO_ACCESS_TOKEN=tms_pat_... -- npx -y @teamso/[email protected]Claude Desktop
Add it to claude_desktop_config.json and restart Claude Desktop:
{
"mcpServers": {
"teamso": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@teamso/[email protected]"
],
"env": {
"TEAMSO_ACCESS_TOKEN": "tms_pat_..."
}
}
}
}Windsurf
Add it under Windsurf → Settings → MCP:
{
"mcpServers": {
"teamso": {
"command": "npx",
"args": [
"-y",
"@teamso/[email protected]"
],
"env": {
"TEAMSO_ACCESS_TOKEN": "tms_pat_..."
}
}
}
}Other clients
Any stdio client can run this command; the token is read from the TEAMSO_ACCESS_TOKEN environment variable:
TEAMSO_ACCESS_TOKEN=tms_pat_... npx -y @teamso/[email protected]Authentication
The package uses a single credential: the personal access token you create on the MCP access page in Teamso. Put it in TEAMSO_ACCESS_TOKEN; the package sends it as the Authorization: Bearer header on every request.
TEAMSO_ACCESS_TOKEN=tms_pat_...With the local package, requests come from your own IP address; if your company restricts IPs, that address must be allowed. Permissions, operations blocked for tokens and revocation work as on the hosted server.
Available tools
The package offers the same 34 tools as the hosted server. The table shows the Teamso REST endpoint each tool calls (relative to TEAMSO_API_BASE_URL); the help tools read the public guide bundle instead of the API.
Since 1.2.0 the package works across every module your permissions allow, through the generic API tools (find_api_endpoints, call_api_read, call_api_write...). The flow, the safety rules and examples are on the hosted server page.
Hosted MCP server · All modules
Help
Searches the Teamso how-to guides. Reads the public guide bundle instead of calling the API.
| Tool | API endpoint | What it does |
|---|---|---|
search_help_articles | GET {TEAMSO_HELP_BASE_URL}/how-to/bundle.{lang}.json | Searches the Teamso guides by keyword; filters by module and role. |
get_help_article | GET {TEAMSO_HELP_BASE_URL}/how-to/bundle.{lang}.json | Returns a full guide with its steps. |
list_help_modules | GET {TEAMSO_HELP_BASE_URL}/how-to/bundle.{lang}.json | Lists the modules that have guides, with each module's article titles and ids. |
Account
Returns the token owner and their permissions.
| Tool | API endpoint | What it does |
|---|---|---|
get_me | GET /user | Your name, email, company, roles, permission codes, manager, department and position. |
Leave
Creating and cancelling a leave request is confirmed with an SMS code sent to your phone: the code is valid for 3 minutes and uses digital credit.
| Tool | API endpoint | What it does |
|---|---|---|
list_leave_types | GET /leave-policy/getListAllLeavePolicyForUserGET /leave-policy/getDetailLeavePolicyForUser/{id} | Leave types you can request and the remaining balance of each. |
get_my_leave_balance | GET /leave-policy/getListAllLeavePolicyForUserGET /leave-policy/getDetailLeavePolicyForUser/{id} | A summary of your leave balance: remaining days per type. |
calculate_leave_days | GET /working-days/getWorkingDaysByMeGET /public-holiday/getPublicHolidayByMeGET /leave/dayCalculator/{workingDaysId}/{publicHolidayId}/{leaveTypeId}/{start}/{end}POST /leave/controlToAddLeave | Calculates how many working days a date range takes and the return-to-work date, using your working calendar and public holidays. |
request_leave_otp | GET /sms/generateToken?checkCredit=true | Sends a confirmation code to your phone (valid for 3 minutes, uses SMS credit). |
create_leave_request | GET /leave/dayCalculator/…POST /leave/controlToAddLeaveGET /sms/checkToken/{code}POST /leave | Verifies the SMS code, recalculates the days and submits the request to the approval chain. |
list_my_leaves | GET /leave/listAllLeavesAdvancedPagination | Your own leave requests, filterable by date and status. |
cancel_leave_request | GET /leave/listAllLeavesAdvancedPaginationGET /sms/checkToken/{code}DELETE /leave/{id} | Deletes a leave request after SMS confirmation; requires the leave delete permission. |
Approvals
Leave requests where it is your turn to decide.
| Tool | API endpoint | What it does |
|---|---|---|
list_pending_approvals | GET /leave/listAllLeavesAdvancedPagination?searchKey=state&searchValue=0 | Leave requests waiting for your approval. |
approve_or_reject_leave | GET /leave/listAllLeavesAdvancedPagination?searchKey=state&searchValue=0PUT /leave/state/{id}/{approve}/{answer} | Approves or rejects a request after checking that it is your turn to decide. A rejection needs a reason. |
Employees
Only employees you are allowed to see.
| Tool | API endpoint | What it does |
|---|---|---|
search_employees | GET /user/list-paginationGET /authorized-employee/list | Finds active colleagues by name or email (accent-insensitive). Without access to the company directory it searches the employees you are responsible for. |
get_employee_profile | GET /user/getUserSummaryByUserId/{userId} | A colleague's work profile: branch, department, position, manager, work location and contact details (the phone number is masked unless you may read it). |
Performance
Goals are linked to a period by its name (the title from list_performance_periods); list the periods before the goal tools.
| Tool | API endpoint | What it does |
|---|---|---|
list_performance_periods | GET /performance-settings | Performance periods, goal entry windows and the evaluation scale. |
list_my_goals | GET /user-goal/my | Your goals in the period and the actions available on each. |
list_team_goals | GET /user-goal/assigned | Goals of the employees you manage or assigned goals to (drafts excluded), with the approvals you can give on each. |
create_user_goal | GET /performance-settingsPOST /user-goal | Adds a draft goal for yourself or a direct report (performance admins: for anyone). |
send_goals_to_approval | POST /user-goal/send-to-approval | Sends your draft (PENDING) goals to your manager for approval. |
approve_goal | GET /user-goal/approve/{goalId} | Approves a goal that is waiting for approval. |
revise_and_approve_goal | GET /user-goal/{goalId}PUT /user-goal/revise-and-approve/{goalId} | Revises a goal (name, description, weight, target) and approves it. |
update_goal_actual_value | GET /performance-settingsPUT /user-goal/{goalId}/actual-value | Enters your actual value on a goal under evaluation. |
update_manager_actual_value | GET /performance-settingsPUT /user-goal/{goalId}/manager-actual-value | Enters the achieved value of an employee's goal as their direct manager or an admin. |
approve_goal_evaluation | GET /performance-settingsPOST /user-goal/approve-evaluation-process | Approves an employee's evaluation for the period at your approval step; at the last step Teamso computes the final score. |
Communication
Announcements visible to you.
| Tool | API endpoint | What it does |
|---|---|---|
list_announcements | GET /dashboard/getAnnouncements | Company and shuttle announcements visible to you, newest first. |
Payroll
Only your own payslips.
| Tool | API endpoint | What it does |
|---|---|---|
list_my_payslips | GET /payroll/getPayrollsByMe-pagination | Your e-payslips and their status, filterable by month or year. |
get_payslip_pdf | GET /payroll/download-file/{payrollId} | Returns a payslip PDF as an embedded resource. |
All modules
The rest of Teamso (expenses, requests, overtime, time tracking, payroll, recruiting, inventory, settings...) through the generic API tools. Only the endpoints your own permissions allow are listed and callable; the read tool cannot change data and the write tool shows a preview first.
| Tool | API endpoint | What it does |
|---|---|---|
find_api_endpoints | GET /mcp-catalog/endpoints?q=&module=&method=&page=&size= | Searches the Teamso API endpoints your permissions allow by keyword (Turkish or English), module, HTTP method or effect (read, write, delete). Each result has the endpoint id, a summary, its effect and whether it needs an SMS code or returns a file. |
list_api_modules | GET /mcp-catalog/modules | Lists the modules you can use and how many endpoints each one offers you. |
describe_api_endpoint | GET /mcp-catalog/endpoint?id={METHOD /path} | Shows an endpoint's parameters, body schema, response type, whether it needs an SMS code, and a ready-made example call. |
call_api_read | GET /mcp-catalog/endpoint?id={METHOD /path}GET /{path} + X-Teamso-Mcp-Intent: readPOST /{path} + X-Teamso-Mcp-Intent: read | Runs read endpoints only and returns the data. The request is marked read-only, so Teamso refuses anything that would change data. Large lists are shortened; files (PDF, Excel, CSV, images) come back embedded, up to 8 MB. |
call_api_write | GET /mcp-catalog/endpoint?id={METHOD /path}GET /sms/checkToken/{code}POST /{path}PUT /{path}PATCH /{path}DELETE /{path} | Creates, changes or deletes records. Without confirm it sends nothing and returns a preview of the request with a schema check; it runs with confirm=true only after you agree. Takes otp_code for actions that need an SMS code and uploads files as base64 (10 MB in total). |
request_sms_code | GET /sms/generateToken?checkCredit=true | After you confirm an action that needs an SMS code, sends a 6-digit verification code to your phone (valid for 3 minutes, uses SMS credit). |
The distributor account's content tools are not in the package; they are served by the hosted server only.
Ready-made prompts
Next to the tools, the server publishes MCP prompts (prompts/list, prompts/get); your client shows them as slash commands or in a prompt picker. A prompt only steers the assistant through the tools: every write still needs your confirmation, and a leave request still needs the SMS code.
| Prompt | Arguments | What it does |
|---|---|---|
request_leave | start (optional)First day of leave: yyyy-MM-dd or words like “tomorrow” (Turkey time).end (optional)Last day of leave (yyyy-MM-dd); empty means the same day as start.leave_type (optional)Leave type name, e.g. “Annual leave”; empty means annual leave.note (optional)Note for the approver. | Creates a leave request for the signed-in user: picks the leave type, shows the working days and the remaining balance, asks you to confirm, then sends the request with the SMS code. Missing dates are asked for. Tool chain: list_leave_typescalculate_leave_daysrequest_leave_otpcreate_leave_request |
review_pending_approvals | Takes no arguments. | Lists the leave requests waiting for your approval as a table and asks you, request by request, whether to approve or reject; it never decides for you. A rejection needs a reason. Tool chain: list_pending_approvalsapprove_or_reject_leave |
Prompts were added in version 1.1.0 of the package, and createMcpServer registers them together with the tools. In your own server use the registerPrompts and PROMPT_NAMES exports (@teamso/teamso-mcp/prompts).
Environment variables
The package reads these environment variables:
| Variable | Required | Description |
|---|---|---|
TEAMSO_ACCESS_TOKEN | Yes | Teamso personal access token (tms_pat_...). |
TEAMSO_API_BASE_URL | No | Teamso API address; change it for a test environment or a private installation.Default: https://api.teamso.com/v1 |
TEAMSO_HELP_BASE_URL | No | Site that serves the guide bundle (/how-to/bundle.en.json).Default: https://teamso.com |
TEAMSO_TOOLSETS | No | Tool groups to serve, comma-separated: core, help, leave, approvals, employees, performance, communication, payroll, api. An unknown name stops the server and lists the valid names.Default: all |
TEAMSO_TOOLSETS=core,leave,apiGitHub and npm
The source code is published on GitHub under the MIT licence and the package on npm.
- GitHub: Teamsocom/Teamso-MCP
- npm: @teamso/teamso-mcp
Using as a library
The package exports its core parts so you can build your own MCP server:
import { TeamsoClient } from "@teamso/teamso-mcp/client";
import { createMcpServer } from "@teamso/teamso-mcp/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const client = new TeamsoClient(process.env.TEAMSO_ACCESS_TOKEN!, "https://api.teamso.com/v1");
const server = createMcpServer(client, { name: "my-teamso-assistant" });
await server.connect(new StdioServerTransport());Exports
| Export | Description |
|---|---|
createMcpServer(client, options?)@teamso/teamso-mcp/server | Creates an McpServer with every tool registered; name, version and instructions are optional. |
TeamsoClient@teamso/teamso-mcp/client | Teamso API client: token, base URL and optional settings. |
TeamsoApiError@teamso/teamso-mcp/client | A request Teamso refused: status, messageCode, apiMessage and the response body. |
registerTools(server, client)@teamso/teamso-mcp/tools | Registers the tools on an existing McpServer. |
TOOL_NAMES@teamso/teamso-mcp/tools | The list of tool names the package offers. |
TOOLSETS, resolveToolsets(toolsets)@teamso/teamso-mcp/tools | The tool groups, and resolveToolsets to validate a selection; createMcpServer and registerTools take a toolsets option. |
registerPrompts(server)@teamso/teamso-mcp/prompts | Registers the ready-made prompts on an existing McpServer. |
PROMPT_NAMES@teamso/teamso-mcp/prompts | The list of prompt names the package offers. |
withJsonSchema2020_12(transport)@teamso/teamso-mcp/server | Rewrites tools/list schemas to JSON Schema 2020-12 on any transport. |
signProxyRequest(input)@teamso/teamso-mcp/client | The trusted-proxy signature, for verifiers and tests. |
VERSION@teamso/teamso-mcp/server | Package version. |
You can also import the parts on their own:
import { TeamsoClient } from "@teamso/teamso-mcp/client";
import { registerTools, TOOL_NAMES } from "@teamso/teamso-mcp/tools";
registerTools(existingMcpServer, new TeamsoClient(token));
console.log(TOOL_NAMES); // ["search_help_articles", "get_help_article", ...]A server that forwards other people's requests can sign the caller's IP so Teamso applies the company IP restriction and the audit log to the real caller. The secret must match the API's security.mcp-proxy.shared-secret (at least 32 characters):
const client = new TeamsoClient(userToken, "https://api.teamso.com/v1", {
trustedProxy: { clientIp: request.ip, sharedSecret: process.env.TEAMSO_MCP_PROXY_SECRET! },
});Self-hosting on your server
Build from source and run it on your own server (Node.js 20+):
git clone https://github.com/Teamsocom/Teamso-MCP.git
cd Teamso-MCP
npm ci
npm run build
export TEAMSO_ACCESS_TOKEN=tms_pat_...
node dist/index.jsPoint your client at the build instead of npx:
{
"mcpServers": {
"teamso": {
"command": "node",
"args": [
"/absolute/path/to/Teamso-MCP/dist/index.js"
],
"env": {
"TEAMSO_ACCESS_TOKEN": "tms_pat_..."
}
}
}
}The package builds itself on install (prepare), so a tagged release can also be installed straight from GitHub:
npm install github:Teamsocom/Teamso-MCP#v1.2.1For a long-running process use a process manager such as systemd or pm2; pass the token as an environment variable or a secret file and never commit it.