Compare commits
3 Commits
098ae2d2bd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1538e14b70 | ||
|
|
87d83ab4c6 | ||
|
|
2652f85bcf |
3
CREDITS
Normal file
3
CREDITS
Normal file
@@ -0,0 +1,3 @@
|
||||
Original project by Manuel Ernst
|
||||
GitHub: https://github.com/SwamiRama/solidtime-mcp-server
|
||||
License: MIT (Copyright (c) 2026 Manuel Ernst)
|
||||
35
README.md
35
README.md
@@ -1,8 +1,6 @@
|
||||
# solidtime-mcp-server
|
||||
|
||||
[](https://github.com/SwamiRama/solidtime-mcp-server/actions/workflows/ci.yml)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://www.npmjs.com/package/solidtime-mcp-server)
|
||||
|
||||
Cloud-hosted MCP server for [SolidTime](https://www.solidtime.io/) — the open-source time tracking app. Start/stop timers, manage time entries, projects, clients, tags, tasks, members, invitations, and organizations directly from Claude, Cursor, or any MCP-compatible client.
|
||||
|
||||
@@ -20,7 +18,7 @@ Cloud-hosted MCP server for [SolidTime](https://www.solidtime.io/) — the open-
|
||||
- **Timezone support** — display and accept times in your local timezone
|
||||
- **Built-in MCP instructions** — the server provides contextual guidance to AI clients for optimal tool usage
|
||||
- **Session management** — per-user sessions with automatic 30-minute expiry
|
||||
- **Docker-ready** — multi-stage Dockerfile and docker-compose included
|
||||
- **Docker-ready** — multi-stage Dockerfile for easy deployment
|
||||
- **Actionable error messages** — every error tells you what to do next
|
||||
- **Zero external dependencies** beyond the MCP SDK (uses native `fetch`)
|
||||
- Works with self-hosted SolidTime instances and the hosted version
|
||||
@@ -37,6 +35,7 @@ Add to your `claude_desktop_config.json`:
|
||||
{
|
||||
"mcpServers": {
|
||||
"solidtime": {
|
||||
"type": "http",
|
||||
"url": "https://your-server.example.com/mcp",
|
||||
"headers": {
|
||||
"x-solidtime-api-token": "your-token-here",
|
||||
@@ -57,6 +56,7 @@ Add to your `.mcp.json`:
|
||||
{
|
||||
"mcpServers": {
|
||||
"solidtime": {
|
||||
"type": "http",
|
||||
"url": "https://your-server.example.com/mcp",
|
||||
"headers": {
|
||||
"x-solidtime-api-token": "your-token-here",
|
||||
@@ -93,26 +93,33 @@ Get your API token from **SolidTime > Settings > API**.
|
||||
|
||||
## Server Deployment
|
||||
|
||||
### Docker Compose (recommended)
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Docker Manual
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
docker build -t solidtime-mcp-server .
|
||||
docker run -p 3000:3000 solidtime-mcp-server
|
||||
docker run -d \
|
||||
-e PORT=3045 \
|
||||
-e SOLIDTIME_API_URL=https://app.solidtime.io \
|
||||
-p 3045:3045 \
|
||||
solidtime-mcp-server
|
||||
```
|
||||
|
||||
### Dokploy / Docker Swarm
|
||||
|
||||
Create an **Application** (not Compose) in Dokploy pointing to your Git repo. Dokploy will build using the Dockerfile and deploy as a Swarm service. Configure in the Dokploy dashboard:
|
||||
|
||||
- **Domain**: your desired hostname, pointing to port `3045`
|
||||
- **Environment variables**: `PORT=3045` and `SOLIDTIME_API_URL`
|
||||
|
||||
> **Note**: Compose-type deployments use `docker compose up` which creates plain containers. If your Dokploy instance runs Traefik with Docker Swarm, use Application type so Traefik's Swarm provider can discover the service.
|
||||
|
||||
### Server Environment Variables
|
||||
|
||||
These are set on the server, not by MCP clients:
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `PORT` | No | `3000` | HTTP server port |
|
||||
| `PORT` | No | `3045` | HTTP server port |
|
||||
| `SOLIDTIME_API_URL` | No | `https://app.solidtime.io` | Default SolidTime API URL (clients can override via header) |
|
||||
|
||||
### Endpoints
|
||||
@@ -260,8 +267,8 @@ Sessions expire after 30 minutes of inactivity. Reconnect to create a new sessio
|
||||
## Development
|
||||
|
||||
```bash
|
||||
git clone https://github.com/SwamiRama/solidtime-mcp-server.git
|
||||
cd solidtime-mcp-server
|
||||
git clone https://git.fraqtal.xyz/danijel/solidtime-mcp.git
|
||||
cd solidtime-mcp
|
||||
npm install
|
||||
npm run dev:http # Run HTTP mode with tsx (dev)
|
||||
npm run dev # Run stdio mode with tsx (dev)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
services:
|
||||
solidtime-mcp:
|
||||
build: .
|
||||
environment:
|
||||
- PORT=3045
|
||||
# Optional: default SolidTime API URL for all sessions.
|
||||
# Clients can override this via the x-solidtime-api-url header.
|
||||
- SOLIDTIME_API_URL=${SOLIDTIME_API_URL:-https://app.solidtime.io}
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3045/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
networks:
|
||||
dokploy-network:
|
||||
external: true
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "solidtime-mcp-server",
|
||||
"version": "1.0.0",
|
||||
"description": "MCP server for SolidTime time tracking — start/stop timers, manage entries, projects, clients, tags, and tasks",
|
||||
"author": "Manuel",
|
||||
"author": "Danijel",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
@@ -52,6 +52,6 @@
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SwamiRama/solidtime-mcp-server"
|
||||
"url": "https://git.fraqtal.xyz/danijel/solidtime-mcp"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
||||
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { createServer } from "./server.js";
|
||||
|
||||
const PORT = parseInt(process.env.PORT || "3000", 10);
|
||||
const PORT = parseInt(process.env.PORT || "3045", 10);
|
||||
const DEFAULT_SOLIDTIME_API_URL = process.env.SOLIDTIME_API_URL;
|
||||
|
||||
interface Session {
|
||||
@@ -134,14 +134,14 @@ const httpServer = http.createServer(async (req, res) => {
|
||||
const mcpServer = await createServer(config);
|
||||
await mcpServer.connect(transport);
|
||||
|
||||
await transport.handleRequest(req, res, parsedBody);
|
||||
|
||||
const sid = transport.sessionId!;
|
||||
sessions.set(sid, { transport, createdAt: Date.now() });
|
||||
|
||||
transport.onclose = () => {
|
||||
sessions.delete(sid);
|
||||
};
|
||||
|
||||
await transport.handleRequest(req, res, parsedBody);
|
||||
} else {
|
||||
// Existing session
|
||||
const session = sessions.get(sessionId);
|
||||
|
||||
Reference in New Issue
Block a user