@@ -7,7 +7,7 @@ MCP server for [SolidTime](https://www.solidtime.io/) — the open-source time t
77
88## Features
99
10- - ** 8 read-only tools by default** , or 22 tools with explicitly enabled writes
10+ - ** 18 read-only tools by default** , or 38 tools with explicitly enabled writes
1111- ** Start/stop timers** with automatic active-timer detection
1212- ** Aggregated reports** grouped by day, week, project, client, and more
1313- ** Auto member_id resolution** — no manual configuration needed
@@ -58,7 +58,7 @@ Get your API token from **SolidTime > Settings > API**.
5858## Codex Configuration
5959
6060Codex starts this server as a local stdio process. It does not need a public
61- MCP URL or an open listening port. Use Node.js 18 or newer.
61+ MCP URL or an open listening port. Use Node.js 20 or newer.
6262
63631 . Build the checkout as above.
64642 . Activate personal API tokens on self-hosted Solidtime if necessary:
@@ -111,7 +111,7 @@ SOLIDTIME_READ_ONLY = "true"
111111 or Codex, then check ` /mcp ` and ask for a read-only report. Registration alone
112112 does not prove that authentication and tool calls work.
113113
114- The default 8 tools cannot change data. Setting ` SOLIDTIME_READ_ONLY=false `
114+ The default 18 tools cannot change data. Setting ` SOLIDTIME_READ_ONLY=false `
115115enables writes in the server; Codex's allowlist must also be changed to expose
116116them. Only do that intentionally with an appropriately permissioned token.
117117
@@ -243,3 +243,123 @@ npm run inspector # Test with MCP Inspector
243243## License
244244
245245MIT
246+ # Employee Expenses and Inline Reports (1.2.0)
247+
248+ The PineCode Solidtime ** 0.21.1** extension adds historical employee expenses.
249+ It is separate from upstream customer billing: the original API ` cost ` field still
250+ means billable revenue. Standard tools continue to work on upstream Solidtime;
251+ expense tools require the extension and return a normal API error on older servers.
252+
253+ - ` solidtime_get_labor_cost_report ` : interactive MCP App plus structured JSON, with dates,
254+ employee/project/client/task/tag filters, grouping, display currency and pagination.
255+ - ` solidtime_get_labor_cost_entries ` : entry details, effective rates, both currencies,
256+ completeness and missing-data flags.
257+ - ` solidtime_get_labor_cost_rates ` : effective-dated employee/project history, including cancellations.
258+ - ` solidtime_get_labor_cost_settings ` : organization expense timezone, project currencies and scoped employee payment currencies.
259+ - ` solidtime_get_current_labor_cost_rates ` : today's personal rates in the organization timezone, scoped to the caller.
260+ - ` solidtime_export_labor_costs ` : dual-currency CSV/PDF as a private MCP resource link.
261+ - ` solidtime_export_employee_report ` : detailed employee PDF with Overview time charts,
262+ Project > Description breakdown, original earnings and payment estimate in the header.
263+ - ` solidtime_list_members ` , ` solidtime_get_organization ` , ` solidtime_get_project ` ,
264+ ` solidtime_get_currencies ` : discover IDs and currencies without guessing.
265+
266+ With ` SOLIDTIME_READ_ONLY=false ` , Owner/Admin may also use
267+ ` solidtime_create_labor_cost_rate ` , ` solidtime_update_labor_cost_rate ` ,
268+ ` solidtime_cancel_labor_cost_rate ` , ` solidtime_update_expense_timezone ` and
269+ ` solidtime_update_project_expense_currency ` and ` solidtime_update_member_payment_currency ` .
270+ The latter accepts ` {id: "member-uuid", payment_currency: "RUB"} ` (or ` null ` to
271+ preserve original rate currencies). It changes a current reporting preference for
272+ all periods, not hourly rates or actual settlements. Rate changes/cancellations can affect
273+ history: confirm the effective interval with the user before invoking them. The UI
274+ widget is read-only and does not expose these mutation controls.
275+
276+ Example: ask for one employee's monthly report with ` currency: "RUB" ` . The report
277+ shows original USD and historically converted RUB side by side. It uses official
278+ CBR rates on each entry's cost date, ** not** the payday rate or a payroll ledger.
279+ Money stays in decimal strings; different original currencies are never added
280+ together. Missing rates or unsupported FX make the subtotal explicitly incomplete.
281+
282+ Payment currency is independent of both rate and display currency: an employee
283+ can earn USD, receive RUB, and still appear in a USD project report. The widget,
284+ structured JSON and CSV/PDF include a separate payment estimate and weighted FX
285+ from the API. Each earning uses its historical daily CBR rate. For example, 6 USD
286+ at 80 RUB/USD and 12 USD at 90 yields 18 USD, 1,560 RUB and 86.66666667 RUB/USD.
287+ The weighting uses unrounded earnings, not calendar days or hours; different
288+ currency pairs stay separate. Missing payment quotes have their own completeness
289+ flag and no invented average. Zero earnings have no weighted rate. On older
290+ extensions without payment fields, the widget shows payment data as unavailable
291+ instead of guessing the employee's payment currency.
292+
293+ For a monthly project/task breakdown, call ` solidtime_get_labor_cost_report ` with
294+ ` date_from: "2026-09-01" ` , ` date_to: "2026-09-30" ` , the employee's ` member_ids ` ,
295+ ` group: "project" ` , ` sub_group: "task" ` , and ` currency: "RUB" ` .
296+ Dates are inclusive cost dates in the organization timezone. Each project and
297+ nested task shows billable hours, original expenses and converted expenses;
298+ parent and child subtotals must not be added together. Only completed billable
299+ work is included, not non-billable work, breaks or running timers. Use the standard
300+ time entry report when all tracked hours are needed.
301+
302+ For the detailed employee time-and-pay PDF, first resolve the ** membership** UUID
303+ with ` solidtime_list_members ` , then call:
304+
305+ ``` json
306+ {
307+ "name" : " solidtime_export_employee_report" ,
308+ "arguments" : {
309+ "member_id" : " bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb" ,
310+ "date_from" : " 2026-09-01" ,
311+ "date_to" : " 2026-09-30"
312+ }
313+ }
314+ ```
315+
316+ The PDF includes the standard Overview time chart, project pie chart and
317+ Project > Description table, with original earnings and the employee's configured
318+ payment-currency estimate at the top. Dates are inclusive persisted cost dates.
319+ Optional project/client/task/tag filters and ` billable ` apply to both sections.
320+ Time includes all matching completed work; earnings still include only billable
321+ work. Breaks/running timers and billing rounding are excluded. Multiple rate
322+ currencies and incomplete rate/FX subtotals remain explicit. Owner/Admin may
323+ select any employee; other members may select only themselves, enforced by the API.
324+
325+ The result is a ` resource_link ` (` solidtime://exports/<random-id> ` ), not a public
326+ download URL. Read it with MCP ` resources/read ` before its ten-minute expiry to
327+ obtain the ` application/pdf ` base64 bytes, or discover active files through
328+ ` resources/list ` . A host can save those bytes locally or
329+ attach them to an explicitly authorized document/Telegram workflow. This server
330+ does not send reports to Telegram or any third-party service. The same PDF is
331+ available in Solidtime's Overview ** Export > Employee PDF** menu after selecting
332+ one member. The deployed Solidtime extension must include ` /labor-costs/employee-report ` ;
333+ older deployments return 404, not a substitute billing PDF.
334+
335+ The inline report keeps the group overview compact on phones. Entry details are
336+ collapsed initially, paginated by 20, and scrolling tables have a bounded height;
337+ the MCP Apps SDK reports actual content size to the host instead of reserving a
338+ full-height canvas. Group/subgroup, date and currency changes preserve the employee filter.
339+
340+ ### MCP App and Security
341+
342+ The report tool advertises ` ui://solidtime/labor-costs.html ` using the standard
343+ [ MCP Apps extension] ( https://modelcontextprotocol.io/extensions/apps/overview ) .
344+ Supporting desktop hosts render the widget inline: dates, currency, grouping,
345+ pages and CSV/PDF downloads stay interactive. Hosts without MCP Apps still receive
346+ the same structured JSON/text. Node ** 20+** is required; the compatible 1.x Apps SDK
347+ is pinned rather than migrating the existing MCP server to SDK 2.x.
348+
349+ The HTML/JavaScript bundle is served locally through MCP, with no CDN, analytics,
350+ direct API connection or token in the iframe. Its CSP declares empty network and
351+ external-resource origin lists. Data is inserted as text, never executable HTML.
352+ All API calls stay pinned to the configured HTTPS origin with redirects blocked;
353+ the server enforces role visibility. Export buffers are capped at 8 MiB and five
354+ files, expire after ten minutes, and live only in process memory. Restarting the
355+ MCP server removes them. Downloads are mediated by the host, not public URLs.
356+
357+ ### Update an Existing Codex Connection
358+
359+ Rebuild with ` npm ci && npm run build ` , retain the existing Keychain launcher or
360+ your configured token injection, then restart ** only the Solidtime MCP server**
361+ from Settings > MCP servers. No token belongs in source or command-line arguments.
362+ If your Codex configuration uses ` enabled_tools ` , add the read tool names above;
363+ otherwise an old allow list hides the new report tools. Keep ` SOLIDTIME_READ_ONLY=true `
364+ for reporting. Reconnection and MCP Apps support depend on the host; a successful
365+ protocol test alone is not proof that an inline widget rendered.
0 commit comments