Sign In

tracetify-mcp

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tracetify-mcp - npm Package Compare versions

Comparing version
0.1.3
to
0.2.0
+1
-1
package.json
{
"name": "tracetify-mcp",
"mcpName": "io.github.tracetify/tracetify-mcp",
"version": "0.1.3",
"version": "0.2.0",
"description": "MCP server for Tracetify — trace how any product actually grew, from inside Claude Code or Cursor.",

@@ -6,0 +6,0 @@ "keywords": [

@@ -39,2 +39,3 @@ # tracetify-mcp

| `get_trace` | free | Poll a running trace |
| `unlock_report` | credits | Permanently unlock a report's full timeline, evidence & SEO detail (idempotent — never charges twice) |

@@ -41,0 +42,0 @@ Fresh traces draw from your Tracetify credit balance — the same balance the

@@ -13,3 +13,3 @@ /**

export function createServer({ apiKey, baseUrl = DEFAULT_BASE, fetchImpl = fetch } = {}) {
const server = new McpServer({ name: 'tracetify', version: '0.1.0' });
const server = new McpServer({ name: 'tracetify', version: '0.2.0' });

@@ -81,2 +81,17 @@ async function call(path, init = {}) {

server.registerTool(
'unlock_report',
{
description:
"Permanently unlock a report's full timeline, evidence and SEO detail for this account. "
+ "Costs credits — quote the exact price to the user first (it is in the report's "
+ "timelineLocked.cost field from read_report) and call this ONLY after they explicitly "
+ "agree to spend. Idempotent: unlocking an already-unlocked report never charges twice. "
+ "Returns the full report. The verdict stays on the website — you are the analyst here.",
inputSchema: { slug: z.string() },
},
async ({ slug }) =>
text(await call(`/api/mcp/v1/reports/${encodeURIComponent(slug)}/unlock`, { method: 'POST' }))
);
server.registerTool(
'get_trace',

@@ -83,0 +98,0 @@ {

@@ -19,3 +19,3 @@ import { describe, expect, it, vi } from 'vitest';

expect(tools.map((t) => t.name).sort()).toEqual(
['get_trace', 'read_report', 'search_reports', 'start_trace']
['get_trace', 'read_report', 'search_reports', 'start_trace', 'unlock_report']
);

@@ -72,3 +72,3 @@ });

const { tools } = await client.listTools();
expect(tools).toHaveLength(4);
expect(tools).toHaveLength(5);
const res = await client.callTool({ name: 'search_reports', arguments: { query: 'x' } });

@@ -79,2 +79,16 @@ expect(res.isError).toBe(true);

});
it('unlock_report posts to the unlock endpoint', async () => {
const fetchImpl = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ charged: true, balance: 219, report: { host: 'weshop.ai' } }),
});
const client = await connected(fetchImpl);
const res = await client.callTool({ name: 'unlock_report', arguments: { slug: 'weshop-ai' } });
expect(fetchImpl).toHaveBeenCalledWith(
'https://api.test/api/mcp/v1/reports/weshop-ai/unlock',
expect.objectContaining({ method: 'POST' })
);
expect(res.content[0].text).toContain('"charged": true');
});
});