Compare commits

..

3 Commits

Author SHA1 Message Date
Danijel
1538e14b70 chore: update authorship and add CREDITS file
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:28:36 +01:00
Danijel
87d83ab4c6 fix: store session after handleRequest so sessionId is initialized
transport.sessionId is only populated during handleRequest(), not
before. Reading it before that call stored sessions under key
`undefined`, causing all subsequent requests to get "Session not found."

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:17:56 +01:00
Danijel
2652f85bcf fix: remove docker-compose and update deployment docs
Remove docker-compose.yml since Dokploy deploys as a Swarm service
using the Dockerfile directly. Update README with Docker and Dokploy
deployment instructions. Fix default port to 3045 in http-server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:28:52 +01:00
5 changed files with 29 additions and 40 deletions

3
CREDITS Normal file
View 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)

View File

@@ -1,8 +1,6 @@
# solidtime-mcp-server
[![CI](https://github.com/SwamiRama/solidtime-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/SwamiRama/solidtime-mcp-server/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![npm](https://img.shields.io/npm/v/solidtime-mcp-server)](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)

View File

@@ -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

View File

@@ -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"
}
}

View File

@@ -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);