reporter-mcp 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,70 @@
1
+ import type { Config } from './config.js';
2
+ export interface ReportFile {
3
+ path: string;
4
+ content: string;
5
+ content_type?: string;
6
+ }
7
+ export interface DeployRequest {
8
+ name: string;
9
+ slug?: string;
10
+ description?: string;
11
+ agent_id: string;
12
+ agent_name?: string;
13
+ entry_file?: string;
14
+ tags?: string[];
15
+ files: ReportFile[];
16
+ }
17
+ export interface UpdateRequest {
18
+ name?: string;
19
+ description?: string;
20
+ tags?: string[];
21
+ files?: ReportFile[];
22
+ }
23
+ export interface Report {
24
+ id: string;
25
+ slug: string;
26
+ name: string;
27
+ description: string | null;
28
+ agent_id: string;
29
+ agent_name: string | null;
30
+ created_at: string;
31
+ updated_at: string;
32
+ version: number;
33
+ entry_file: string;
34
+ file_count: number;
35
+ total_size_bytes: number;
36
+ tags: string[];
37
+ }
38
+ export interface FileInfo {
39
+ path: string;
40
+ size: number;
41
+ uploaded: string;
42
+ }
43
+ export declare class ApiClient {
44
+ private config;
45
+ constructor(config: Config);
46
+ private request;
47
+ deployReport(request: DeployRequest): Promise<{
48
+ report: Report;
49
+ url: string;
50
+ }>;
51
+ updateReport(slug: string, request: UpdateRequest): Promise<{
52
+ report: Report;
53
+ url: string;
54
+ }>;
55
+ listReports(options?: {
56
+ agent_id?: string;
57
+ search?: string;
58
+ limit?: number;
59
+ offset?: number;
60
+ }): Promise<{
61
+ reports: Report[];
62
+ }>;
63
+ getReport(slug: string): Promise<{
64
+ report: Report;
65
+ files: FileInfo[];
66
+ }>;
67
+ deleteReport(slug: string): Promise<{
68
+ success: boolean;
69
+ }>;
70
+ }
@@ -0,0 +1,51 @@
1
+ export class ApiClient {
2
+ config;
3
+ constructor(config) {
4
+ this.config = config;
5
+ }
6
+ async request(path, options = {}) {
7
+ const url = `${this.config.apiUrl}${path}`;
8
+ const headers = new Headers(options.headers);
9
+ headers.set('X-API-Key', this.config.apiKey);
10
+ headers.set('Content-Type', 'application/json');
11
+ const response = await fetch(url, {
12
+ ...options,
13
+ headers,
14
+ });
15
+ if (!response.ok) {
16
+ const error = await response.json().catch(() => ({ error: response.statusText }));
17
+ throw new Error(error.error || `HTTP ${response.status}`);
18
+ }
19
+ return response.json();
20
+ }
21
+ async deployReport(request) {
22
+ return this.request('/api/deploy', {
23
+ method: 'POST',
24
+ body: JSON.stringify(request),
25
+ });
26
+ }
27
+ async updateReport(slug, request) {
28
+ return this.request(`/api/deploy/${slug}`, {
29
+ method: 'PUT',
30
+ body: JSON.stringify(request),
31
+ });
32
+ }
33
+ async listReports(options) {
34
+ const params = new URLSearchParams();
35
+ for (const [key, value] of Object.entries(options ?? {})) {
36
+ if (value !== undefined) {
37
+ params.set(key, String(value));
38
+ }
39
+ }
40
+ const query = params.toString();
41
+ return this.request(`/api/reports${query ? `?${query}` : ''}`);
42
+ }
43
+ async getReport(slug) {
44
+ return this.request(`/api/reports/${slug}`);
45
+ }
46
+ async deleteReport(slug) {
47
+ return this.request(`/api/reports/${slug}`, {
48
+ method: 'DELETE',
49
+ });
50
+ }
51
+ }
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ declare const ConfigSchema: z.ZodObject<{
3
+ apiKey: z.ZodString;
4
+ apiUrl: z.ZodString;
5
+ agentId: z.ZodOptional<z.ZodString>;
6
+ agentName: z.ZodOptional<z.ZodString>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ apiKey: string;
9
+ apiUrl: string;
10
+ agentId?: string | undefined;
11
+ agentName?: string | undefined;
12
+ }, {
13
+ apiKey: string;
14
+ apiUrl: string;
15
+ agentId?: string | undefined;
16
+ agentName?: string | undefined;
17
+ }>;
18
+ export type Config = z.infer<typeof ConfigSchema>;
19
+ export declare function loadConfig(): Config;
20
+ export {};
package/dist/config.js ADDED
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ const ConfigSchema = z.object({
3
+ apiKey: z.string().min(1, 'REPORTER_API_KEY is required'),
4
+ apiUrl: z.string().url('REPORTER_API_URL must be a valid URL'),
5
+ agentId: z.string().optional(),
6
+ agentName: z.string().optional(),
7
+ });
8
+ export function loadConfig() {
9
+ const config = {
10
+ apiKey: process.env.REPORTER_API_KEY || '',
11
+ apiUrl: process.env.REPORTER_API_URL || '',
12
+ agentId: process.env.AGENT_ID || '',
13
+ agentName: process.env.AGENT_NAME,
14
+ };
15
+ return ConfigSchema.parse(config);
16
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
+ import { loadConfig } from './config.js';
6
+ import { ApiClient } from './api-client.js';
7
+ import { deployReportSchema, updateReportSchema, createDeployTool, createUpdateTool, } from './tools/deploy.js';
8
+ import { listReportsSchema, getReportSchema, deleteReportSchema, createListTool, createGetTool, createDeleteTool, } from './tools/reports.js';
9
+ const config = loadConfig();
10
+ const client = new ApiClient(config);
11
+ const deployTool = createDeployTool(client, config);
12
+ const updateTool = createUpdateTool(client);
13
+ const listTool = createListTool(client);
14
+ const getTool = createGetTool(client);
15
+ const deleteTool = createDeleteTool(client);
16
+ const server = new Server({
17
+ name: 'reporter',
18
+ version: '1.0.0',
19
+ }, {
20
+ capabilities: {
21
+ tools: {},
22
+ },
23
+ });
24
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
25
+ return {
26
+ tools: [
27
+ {
28
+ name: 'deploy_report',
29
+ description: 'Deploy an HTML report to the Reporter hosting system. Provide either HTML content directly or a folder path containing report files. Returns a stable URL for viewing.',
30
+ inputSchema: {
31
+ type: 'object',
32
+ properties: {
33
+ name: {
34
+ type: 'string',
35
+ description: 'Name of the report',
36
+ },
37
+ slug: {
38
+ type: 'string',
39
+ description: 'URL-friendly identifier (auto-generated if not provided)',
40
+ },
41
+ description: {
42
+ type: 'string',
43
+ description: 'Description of the report',
44
+ },
45
+ content: {
46
+ type: 'string',
47
+ description: 'HTML content string (for single-file reports)',
48
+ },
49
+ folder_path: {
50
+ type: 'string',
51
+ description: 'Path to folder containing report files (HTML, CSS, JS, images)',
52
+ },
53
+ entry_file: {
54
+ type: 'string',
55
+ description: 'Entry file name (default: index.html)',
56
+ },
57
+ tags: {
58
+ type: 'array',
59
+ items: { type: 'string' },
60
+ description: 'Tags for categorization',
61
+ },
62
+ agent_id: {
63
+ type: 'string',
64
+ description: 'Unique identifier for the agent deploying this report (e.g., "research-agent", "data-analyzer")',
65
+ },
66
+ agent_name: {
67
+ type: 'string',
68
+ description: 'Human-readable name of the agent (e.g., "Research Agent", "Data Analyzer")',
69
+ },
70
+ },
71
+ required: ['name', 'agent_id', 'agent_name'],
72
+ },
73
+ },
74
+ {
75
+ name: 'update_report',
76
+ description: 'Update an existing report. The URL remains stable. You can update metadata, content, or both.',
77
+ inputSchema: {
78
+ type: 'object',
79
+ properties: {
80
+ slug: {
81
+ type: 'string',
82
+ description: 'Slug of the report to update',
83
+ },
84
+ name: {
85
+ type: 'string',
86
+ description: 'New name for the report',
87
+ },
88
+ description: {
89
+ type: 'string',
90
+ description: 'New description',
91
+ },
92
+ content: {
93
+ type: 'string',
94
+ description: 'New HTML content (for single-file update)',
95
+ },
96
+ folder_path: {
97
+ type: 'string',
98
+ description: 'Path to folder with new files',
99
+ },
100
+ tags: {
101
+ type: 'array',
102
+ items: { type: 'string' },
103
+ description: 'New tags',
104
+ },
105
+ },
106
+ required: ['slug'],
107
+ },
108
+ },
109
+ {
110
+ name: 'list_reports',
111
+ description: 'List all reports, optionally filtered by agent ID or search terms.',
112
+ inputSchema: {
113
+ type: 'object',
114
+ properties: {
115
+ agent_id: {
116
+ type: 'string',
117
+ description: 'Filter by agent ID',
118
+ },
119
+ search: {
120
+ type: 'string',
121
+ description: 'Search in name, description, and tags',
122
+ },
123
+ limit: {
124
+ type: 'number',
125
+ description: 'Maximum number of results (default: 50)',
126
+ },
127
+ offset: {
128
+ type: 'number',
129
+ description: 'Offset for pagination',
130
+ },
131
+ },
132
+ },
133
+ },
134
+ {
135
+ name: 'get_report',
136
+ description: 'Get detailed information about a specific report, including file list.',
137
+ inputSchema: {
138
+ type: 'object',
139
+ properties: {
140
+ slug: {
141
+ type: 'string',
142
+ description: 'Slug of the report to retrieve',
143
+ },
144
+ },
145
+ required: ['slug'],
146
+ },
147
+ },
148
+ {
149
+ name: 'delete_report',
150
+ description: 'Delete a report and all its associated files.',
151
+ inputSchema: {
152
+ type: 'object',
153
+ properties: {
154
+ slug: {
155
+ type: 'string',
156
+ description: 'Slug of the report to delete',
157
+ },
158
+ },
159
+ required: ['slug'],
160
+ },
161
+ },
162
+ ],
163
+ };
164
+ });
165
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
166
+ const { name, arguments: args } = request.params;
167
+ try {
168
+ let result;
169
+ switch (name) {
170
+ case 'deploy_report':
171
+ result = await deployTool(deployReportSchema.parse(args));
172
+ break;
173
+ case 'update_report':
174
+ result = await updateTool(updateReportSchema.parse(args));
175
+ break;
176
+ case 'list_reports':
177
+ result = await listTool(listReportsSchema.parse(args || {}));
178
+ break;
179
+ case 'get_report':
180
+ result = await getTool(getReportSchema.parse(args));
181
+ break;
182
+ case 'delete_report':
183
+ result = await deleteTool(deleteReportSchema.parse(args));
184
+ break;
185
+ default:
186
+ throw new Error(`Unknown tool: ${name}`);
187
+ }
188
+ return {
189
+ content: [
190
+ {
191
+ type: 'text',
192
+ text: JSON.stringify(result, null, 2),
193
+ },
194
+ ],
195
+ };
196
+ }
197
+ catch (error) {
198
+ const message = error instanceof Error ? error.message : 'Unknown error';
199
+ return {
200
+ content: [
201
+ {
202
+ type: 'text',
203
+ text: JSON.stringify({ error: message }),
204
+ },
205
+ ],
206
+ isError: true,
207
+ };
208
+ }
209
+ });
210
+ async function main() {
211
+ const transport = new StdioServerTransport();
212
+ await server.connect(transport);
213
+ console.error('Reporter MCP server running');
214
+ }
215
+ main().catch((error) => {
216
+ console.error('Fatal error:', error);
217
+ process.exit(1);
218
+ });
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ import type { ApiClient } from '../api-client.js';
3
+ import type { Config } from '../config.js';
4
+ export declare const deployReportSchema: z.ZodObject<{
5
+ name: z.ZodString;
6
+ slug: z.ZodOptional<z.ZodString>;
7
+ description: z.ZodOptional<z.ZodString>;
8
+ content: z.ZodOptional<z.ZodString>;
9
+ folder_path: z.ZodOptional<z.ZodString>;
10
+ entry_file: z.ZodOptional<z.ZodString>;
11
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
12
+ agent_id: z.ZodOptional<z.ZodString>;
13
+ agent_name: z.ZodOptional<z.ZodString>;
14
+ }, "strip", z.ZodTypeAny, {
15
+ name: string;
16
+ agent_id?: string | undefined;
17
+ slug?: string | undefined;
18
+ description?: string | undefined;
19
+ content?: string | undefined;
20
+ folder_path?: string | undefined;
21
+ entry_file?: string | undefined;
22
+ tags?: string[] | undefined;
23
+ agent_name?: string | undefined;
24
+ }, {
25
+ name: string;
26
+ agent_id?: string | undefined;
27
+ slug?: string | undefined;
28
+ description?: string | undefined;
29
+ content?: string | undefined;
30
+ folder_path?: string | undefined;
31
+ entry_file?: string | undefined;
32
+ tags?: string[] | undefined;
33
+ agent_name?: string | undefined;
34
+ }>;
35
+ export declare const updateReportSchema: z.ZodObject<{
36
+ slug: z.ZodString;
37
+ name: z.ZodOptional<z.ZodString>;
38
+ description: z.ZodOptional<z.ZodString>;
39
+ content: z.ZodOptional<z.ZodString>;
40
+ folder_path: z.ZodOptional<z.ZodString>;
41
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
42
+ }, "strip", z.ZodTypeAny, {
43
+ slug: string;
44
+ name?: string | undefined;
45
+ description?: string | undefined;
46
+ content?: string | undefined;
47
+ folder_path?: string | undefined;
48
+ tags?: string[] | undefined;
49
+ }, {
50
+ slug: string;
51
+ name?: string | undefined;
52
+ description?: string | undefined;
53
+ content?: string | undefined;
54
+ folder_path?: string | undefined;
55
+ tags?: string[] | undefined;
56
+ }>;
57
+ export declare function createDeployTool(client: ApiClient, config: Config): (input: z.infer<typeof deployReportSchema>) => Promise<{
58
+ success: boolean;
59
+ report: import("../api-client.js").Report;
60
+ url: string;
61
+ message: string;
62
+ }>;
63
+ export declare function createUpdateTool(client: ApiClient): (input: z.infer<typeof updateReportSchema>) => Promise<{
64
+ success: boolean;
65
+ report: import("../api-client.js").Report;
66
+ url: string;
67
+ message: string;
68
+ }>;
@@ -0,0 +1,158 @@
1
+ import { z } from 'zod';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ export const deployReportSchema = z.object({
5
+ name: z.string().describe('Name of the report'),
6
+ slug: z.string().optional().describe('URL-friendly identifier (auto-generated if not provided)'),
7
+ description: z.string().optional().describe('Description of the report'),
8
+ content: z.string().optional().describe('HTML content string (for single-file reports)'),
9
+ folder_path: z.string().optional().describe('Path to folder containing report files'),
10
+ entry_file: z.string().optional().describe('Entry file name (default: index.html)'),
11
+ tags: z.array(z.string()).optional().describe('Tags for categorization'),
12
+ agent_id: z.string().optional().describe('Unique identifier for the agent deploying this report'),
13
+ agent_name: z.string().optional().describe('Human-readable name of the agent'),
14
+ });
15
+ export const updateReportSchema = z.object({
16
+ slug: z.string().describe('Slug of the report to update'),
17
+ name: z.string().optional().describe('New name for the report'),
18
+ description: z.string().optional().describe('New description'),
19
+ content: z.string().optional().describe('New HTML content (for single-file update)'),
20
+ folder_path: z.string().optional().describe('Path to folder with new files'),
21
+ tags: z.array(z.string()).optional().describe('New tags'),
22
+ });
23
+ function getMimeType(filePath) {
24
+ const ext = path.extname(filePath).toLowerCase();
25
+ const mimeTypes = {
26
+ '.html': 'text/html',
27
+ '.css': 'text/css',
28
+ '.js': 'application/javascript',
29
+ '.json': 'application/json',
30
+ '.png': 'image/png',
31
+ '.jpg': 'image/jpeg',
32
+ '.jpeg': 'image/jpeg',
33
+ '.gif': 'image/gif',
34
+ '.svg': 'image/svg+xml',
35
+ '.webp': 'image/webp',
36
+ '.ico': 'image/x-icon',
37
+ '.woff': 'font/woff',
38
+ '.woff2': 'font/woff2',
39
+ '.ttf': 'font/ttf',
40
+ '.eot': 'application/vnd.ms-fontobject',
41
+ '.pdf': 'application/pdf',
42
+ };
43
+ return mimeTypes[ext] || 'application/octet-stream';
44
+ }
45
+ function isBinaryFile(filePath) {
46
+ const ext = path.extname(filePath).toLowerCase();
47
+ const binaryExtensions = [
48
+ '.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico',
49
+ '.woff', '.woff2', '.ttf', '.eot', '.pdf',
50
+ ];
51
+ return binaryExtensions.includes(ext);
52
+ }
53
+ async function verifyFolderExists(folderPath) {
54
+ const resolvedPath = path.resolve(folderPath);
55
+ try {
56
+ await fs.access(resolvedPath);
57
+ return resolvedPath;
58
+ }
59
+ catch {
60
+ throw new Error(`Folder not found: ${resolvedPath}`);
61
+ }
62
+ }
63
+ async function readFolderFiles(folderPath) {
64
+ const files = [];
65
+ async function readDir(dir, basePath = '') {
66
+ const entries = await fs.readdir(dir, { withFileTypes: true });
67
+ for (const entry of entries) {
68
+ const fullPath = path.join(dir, entry.name);
69
+ const relativePath = path.join(basePath, entry.name);
70
+ if (entry.isDirectory()) {
71
+ await readDir(fullPath, relativePath);
72
+ }
73
+ else if (entry.isFile()) {
74
+ const isBinary = isBinaryFile(fullPath);
75
+ const content = await fs.readFile(fullPath, isBinary ? 'base64' : 'utf-8');
76
+ files.push({
77
+ path: relativePath.replace(/\\/g, '/'),
78
+ content: isBinary ? `data:${getMimeType(fullPath)};base64,${content}` : content,
79
+ content_type: getMimeType(fullPath),
80
+ });
81
+ }
82
+ }
83
+ }
84
+ await readDir(folderPath);
85
+ return files;
86
+ }
87
+ export function createDeployTool(client, config) {
88
+ return async (input) => {
89
+ if (!input.content && !input.folder_path) {
90
+ throw new Error('Either content or folder_path must be provided');
91
+ }
92
+ const entryFile = input.entry_file || 'index.html';
93
+ let files;
94
+ if (input.folder_path) {
95
+ const resolvedPath = await verifyFolderExists(input.folder_path);
96
+ files = await readFolderFiles(resolvedPath);
97
+ }
98
+ else {
99
+ files = [
100
+ {
101
+ path: entryFile,
102
+ content: input.content,
103
+ content_type: 'text/html',
104
+ },
105
+ ];
106
+ }
107
+ const agentId = input.agent_id || config.agentId;
108
+ if (!agentId) {
109
+ throw new Error('agent_id is required - provide it as a parameter or set AGENT_ID env var');
110
+ }
111
+ const result = await client.deployReport({
112
+ name: input.name,
113
+ slug: input.slug,
114
+ description: input.description,
115
+ agent_id: agentId,
116
+ agent_name: input.agent_name || config.agentName,
117
+ entry_file: entryFile,
118
+ tags: input.tags,
119
+ files,
120
+ });
121
+ return {
122
+ success: true,
123
+ report: result.report,
124
+ url: result.url,
125
+ message: `Report "${result.report.name}" deployed successfully. View at: ${result.url}`,
126
+ };
127
+ };
128
+ }
129
+ export function createUpdateTool(client) {
130
+ return async (input) => {
131
+ let files;
132
+ if (input.folder_path) {
133
+ const resolvedPath = await verifyFolderExists(input.folder_path);
134
+ files = await readFolderFiles(resolvedPath);
135
+ }
136
+ else if (input.content) {
137
+ files = [
138
+ {
139
+ path: 'index.html',
140
+ content: input.content,
141
+ content_type: 'text/html',
142
+ },
143
+ ];
144
+ }
145
+ const result = await client.updateReport(input.slug, {
146
+ name: input.name,
147
+ description: input.description,
148
+ tags: input.tags,
149
+ files,
150
+ });
151
+ return {
152
+ success: true,
153
+ report: result.report,
154
+ url: result.url,
155
+ message: `Report "${result.report.name}" updated successfully (version ${result.report.version}). View at: ${result.url}`,
156
+ };
157
+ };
158
+ }
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod';
2
+ import type { ApiClient } from '../api-client.js';
3
+ export declare const listReportsSchema: z.ZodObject<{
4
+ agent_id: z.ZodOptional<z.ZodString>;
5
+ search: z.ZodOptional<z.ZodString>;
6
+ limit: z.ZodOptional<z.ZodNumber>;
7
+ offset: z.ZodOptional<z.ZodNumber>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ agent_id?: string | undefined;
10
+ search?: string | undefined;
11
+ limit?: number | undefined;
12
+ offset?: number | undefined;
13
+ }, {
14
+ agent_id?: string | undefined;
15
+ search?: string | undefined;
16
+ limit?: number | undefined;
17
+ offset?: number | undefined;
18
+ }>;
19
+ export declare const getReportSchema: z.ZodObject<{
20
+ slug: z.ZodString;
21
+ }, "strip", z.ZodTypeAny, {
22
+ slug: string;
23
+ }, {
24
+ slug: string;
25
+ }>;
26
+ export declare const deleteReportSchema: z.ZodObject<{
27
+ slug: z.ZodString;
28
+ }, "strip", z.ZodTypeAny, {
29
+ slug: string;
30
+ }, {
31
+ slug: string;
32
+ }>;
33
+ export declare function createListTool(client: ApiClient): (input: z.infer<typeof listReportsSchema>) => Promise<{
34
+ count: number;
35
+ reports: import("../api-client.js").Report[];
36
+ }>;
37
+ export declare function createGetTool(client: ApiClient): (input: z.infer<typeof getReportSchema>) => Promise<{
38
+ report: import("../api-client.js").Report;
39
+ files: import("../api-client.js").FileInfo[];
40
+ }>;
41
+ export declare function createDeleteTool(client: ApiClient): (input: z.infer<typeof deleteReportSchema>) => Promise<{
42
+ success: boolean;
43
+ message: string;
44
+ }>;
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+ export const listReportsSchema = z.object({
3
+ agent_id: z.string().optional().describe('Filter by agent ID'),
4
+ search: z.string().optional().describe('Search in name, description, and tags'),
5
+ limit: z.number().optional().describe('Maximum number of results (default: 50)'),
6
+ offset: z.number().optional().describe('Offset for pagination'),
7
+ });
8
+ export const getReportSchema = z.object({
9
+ slug: z.string().describe('Slug of the report to retrieve'),
10
+ });
11
+ export const deleteReportSchema = z.object({
12
+ slug: z.string().describe('Slug of the report to delete'),
13
+ });
14
+ export function createListTool(client) {
15
+ return async (input) => {
16
+ const result = await client.listReports(input);
17
+ return {
18
+ count: result.reports.length,
19
+ reports: result.reports,
20
+ };
21
+ };
22
+ }
23
+ export function createGetTool(client) {
24
+ return async (input) => {
25
+ return client.getReport(input.slug);
26
+ };
27
+ }
28
+ export function createDeleteTool(client) {
29
+ return async (input) => {
30
+ await client.deleteReport(input.slug);
31
+ return {
32
+ success: true,
33
+ message: `Report "${input.slug}" deleted successfully`,
34
+ };
35
+ };
36
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "reporter-mcp",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "description": "MCP server for deploying HTML reports to Reporter hosting system",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "reporter-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/44-pixels/agent-reporter.git"
16
+ },
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "prepublishOnly": "npm run build",
20
+ "start": "node dist/index.js",
21
+ "dev": "tsx watch src/index.ts"
22
+ },
23
+ "keywords": [
24
+ "mcp",
25
+ "reporter",
26
+ "html-reports",
27
+ "claude",
28
+ "ai-agents"
29
+ ],
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "@modelcontextprotocol/sdk": "^1.0.0",
33
+ "zod": "^3.23.8"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^20.11.0",
37
+ "tsx": "^4.7.0",
38
+ "typescript": "^5.3.3"
39
+ }
40
+ }