canary-agent 0.1.2 → 0.1.3

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.
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- #!/usr/bin/env node
3
2
  "use strict";
4
3
 
5
4
  // src/journal/server.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/journal/server.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Canary MCP Journal Server — stdio transport.\n *\n * Tools:\n * canary_annotate — Save/read/list/clear local notes about API experiences.\n * canary_report — Submit structured feedback to the Canary backend.\n *\n * All logging goes to stderr to avoid corrupting the MCP protocol.\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n readFileSync,\n writeFileSync,\n mkdirSync,\n unlinkSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n// Redirect console to stderr to prevent stdout corruption\nconsole.log = (...args: any[]) => console.error(...args);\nconsole.info = (...args: any[]) => console.error(...args);\n\nconst FETCH_TIMEOUT_MS = 15_000;\n\n// ─── Annotations (local persistence) ────────────────────────────────\n\nfunction getAnnotationsDir(): string {\n const dir = join(homedir(), \".canary\", \"annotations\");\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\nfunction annotationPath(id: string): string {\n const safe = id.replace(/\\//g, \"--\");\n return join(getAnnotationsDir(), `${safe}.json`);\n}\n\nfunction readAnnotation(id: string): any | null {\n try {\n return JSON.parse(readFileSync(annotationPath(id), \"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeAnnotation(\n id: string,\n note: string\n): { id: string; note: string; updatedAt: string } {\n const data = { id, note, updatedAt: new Date().toISOString() };\n writeFileSync(annotationPath(id), JSON.stringify(data, null, 2));\n return data;\n}\n\nfunction clearAnnotation(id: string): boolean {\n try {\n unlinkSync(annotationPath(id));\n return true;\n } catch {\n return false;\n }\n}\n\nfunction listAnnotations(): any[] {\n const dir = getAnnotationsDir();\n try {\n return readdirSync(dir)\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => {\n try {\n return JSON.parse(readFileSync(join(dir, f), \"utf8\"));\n } catch {\n return null;\n }\n })\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n// ─── Tool definitions ────────────────────────────────────────────────\n\nconst CANARY_ANNOTATE_TOOL = {\n name: \"canary_annotate\",\n description:\n \"REQUIRED: Call this for every HTTP request you make to an external API. \" +\n \"Call it BEFORE the request with your intent (what you're about to do and why), \" +\n \"then call it AFTER with what happened (status, errors, and what you decided to do next). \" +\n \"Notes persist across sessions. Use provider/endpoint IDs like 'stripe/charges'.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n id: {\n type: \"string\",\n description:\n 'Identifier for the annotation (e.g. \"stripe/charges\", \"openai/chat\", \"github/repos\"). ' +\n \"Use provider/endpoint style.\",\n },\n intent: {\n type: \"string\",\n description:\n \"BEFORE the call: What are you about to do and why? \" +\n '(e.g. \"Fetching customer list from Stripe to find overdue invoices for the billing report\")',\n },\n note: {\n type: \"string\",\n description:\n \"AFTER the call: What happened? Include status code, response shape, errors, latency. \" +\n \"If the call failed, describe what you decided to do next — did you retry, \" +\n \"try a different endpoint, or switch to a different service entirely?\",\n },\n clear: {\n type: \"boolean\",\n description: \"Set true to delete the annotation for this id.\",\n },\n list: {\n type: \"boolean\",\n description: \"Set true to list all saved annotations.\",\n },\n },\n required: [],\n },\n};\n\nconst CANARY_REPORT_TOOL = {\n name: \"canary_report\",\n description:\n \"REQUIRED: Call this once when your task is complete to compile your \" +\n \"canary_annotate notes into structured feedback. Tell the full story: \" +\n \"what you intended to do, what actually happened, and every decision you made \" +\n \"along the way — especially when things went wrong. Your report earns credits \" +\n \"and improves API documentation for all agents.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n session_id: {\n type: \"string\",\n description:\n \"Session/task ID to link this report to HTTP telemetry. Pass the skill_execution_id or run ID.\",\n },\n intent: {\n type: \"string\",\n description:\n \"What was your plan going in? Describe your original approach before making any calls. \" +\n '(e.g. \"I planned to fetch Stripe charges, join them with customer emails, and generate a CSV billing report\")',\n },\n task_goal: {\n type: \"string\",\n description:\n 'What were you trying to accomplish? (e.g. \"Create a Stripe charge for $50 and send an SMS confirmation via Twilio\")',\n },\n outcome: {\n type: \"string\",\n enum: [\"success\", \"partial\", \"failure\", \"blocked\"],\n description: \"Did the task succeed?\",\n },\n apis_used: {\n type: \"string\",\n description:\n 'Which APIs did you call? List provider and key endpoints. (e.g. \"Stripe POST /v1/charges, Twilio POST /Messages.json\")',\n },\n what_worked: {\n type: \"string\",\n description:\n 'What went smoothly? Mention specific endpoints or features. (e.g. \"Stripe charge creation returned clear response with charge ID\")',\n },\n what_failed: {\n type: \"string\",\n description:\n 'What went wrong? Include error codes, status, and messages. (e.g. \"POST /v1/refunds returned 400: Charge already refunded\")',\n },\n error_handling: {\n type: \"string\",\n description:\n \"How did you handle each error? For every failure, describe the decision you made: \" +\n \"did you retry the same call, try a different endpoint on the same API, \" +\n \"or give up on that approach? \" +\n '(e.g. \"After /v1/charges returned 401, I tried /v1/payment_intents as an alternative but that also required auth. ' +\n 'I then tried the /v1/invoices endpoint hoping it had different permissions, but got the same 401.\")',\n },\n service_switch: {\n type: \"string\",\n description:\n \"If an API was completely blocked, did you switch to a different service or provider to accomplish the same goal? \" +\n \"Describe what you switched to and why. \" +\n '(e.g. \"Stripe was fully blocked so I switched to the PayPal Orders API to process the payment instead. ' +\n 'PayPal returned 200 and the order was created successfully.\")',\n },\n friction: {\n type: \"string\",\n description:\n \"The single biggest pain point. (e.g. \\\"Stripe charge object doesn't show refund status\\\")\",\n },\n suggestion: {\n type: \"string\",\n description:\n 'How could the API improve? (e.g. \"Add a refund_status field to the charge object\")',\n },\n },\n required: [\"task_goal\", \"outcome\", \"apis_used\"],\n },\n};\n\n// ─── Server config ───────────────────────────────────────────────────\n\ninterface ServerConfig {\n apiKey: string;\n endpoint?: string;\n sessionId?: string;\n agentName?: string;\n}\n\nfunction parseArgs(): ServerConfig {\n const args = process.argv.slice(2);\n let apiKey = process.env.CANARY_API_KEY || \"\";\n let endpoint = process.env.CANARY_ENDPOINT || \"http://localhost:8002\";\n let sessionId = process.env.CANARY_SESSION_ID;\n let agentName = process.env.CANARY_AGENT_NAME;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--api-key\" && args[i + 1]) apiKey = args[++i];\n else if (args[i] === \"--endpoint\" && args[i + 1]) endpoint = args[++i];\n else if (args[i] === \"--session-id\" && args[i + 1]) sessionId = args[++i];\n else if (args[i] === \"--agent-name\" && args[i + 1]) agentName = args[++i];\n else if (args[i].startsWith(\"--api-key=\"))\n apiKey = args[i].substring(\"--api-key=\".length);\n else if (args[i].startsWith(\"--endpoint=\"))\n endpoint = args[i].substring(\"--endpoint=\".length);\n else if (args[i].startsWith(\"--session-id=\"))\n sessionId = args[i].substring(\"--session-id=\".length);\n else if (args[i].startsWith(\"--agent-name=\"))\n agentName = args[i].substring(\"--agent-name=\".length);\n }\n\n if (!apiKey) {\n console.error(\"Error: --api-key or CANARY_API_KEY required\");\n process.exit(1);\n }\n\n return { apiKey, endpoint, sessionId, agentName };\n}\n\n// ─── Backend communication ───────────────────────────────────────────\n\nasync function postEvents(\n config: ServerConfig,\n events: any[]\n): Promise<any> {\n const url = `${config.endpoint}/v1/events`;\n const body = JSON.stringify({ events, sdk_version: \"0.1.0\" });\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n },\n body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`POST /v1/events failed: ${res.status} ${text}`);\n }\n\n return res.json();\n}\n\n// ─── Handlers ────────────────────────────────────────────────────────\n\nfunction handleAnnotate(args: Record<string, any>) {\n const { id, note, clear, list } = args;\n\n if (list) {\n const annotations = listAnnotations();\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n { annotations, total: annotations.length },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n if (!id) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"Missing required parameter: id. Provide a provider/endpoint id or use list mode.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n // Validate id\n if (id.length > 200) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error: \"ID too long (max 200 characters).\",\n }),\n },\n ],\n isError: true,\n };\n }\n if (!/^[a-zA-Z0-9._\\-\\/]+$/.test(id)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"ID contains invalid characters. Use alphanumeric, hyphens, underscores, dots, and slashes.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n if (clear) {\n const removed = clearAnnotation(id);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n status: removed ? \"cleared\" : \"not_found\",\n id,\n }),\n },\n ],\n };\n }\n\n if (note) {\n const saved = writeAnnotation(id, note);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"saved\", annotation: saved }, null, 2),\n },\n ],\n };\n }\n\n // Read mode\n const annotation = readAnnotation(id);\n if (annotation) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ annotation }, null, 2),\n },\n ],\n };\n }\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"no_annotation\", id }),\n },\n ],\n };\n}\n\nfunction buildFeedbackEvent(args: Record<string, any>, config: ServerConfig) {\n const outcome = args.outcome as string;\n const worked = outcome === \"success\" || outcome === \"partial\";\n\n const contextParts: string[] = [];\n if (args.intent) contextParts.push(`Intent: ${args.intent}`);\n contextParts.push(`Goal: ${args.task_goal}`);\n contextParts.push(`APIs: ${args.apis_used}`);\n contextParts.push(`Outcome: ${outcome}`);\n if (args.what_worked) contextParts.push(`Worked: ${args.what_worked}`);\n if (args.what_failed) contextParts.push(`Failed: ${args.what_failed}`);\n if (args.error_handling) contextParts.push(`Error Handling: ${args.error_handling}`);\n if (args.service_switch) contextParts.push(`Service Switch: ${args.service_switch}`);\n if (args.suggestion) contextParts.push(`Suggestion: ${args.suggestion}`);\n\n const frictionPoints: string[] = [];\n if (args.friction) frictionPoints.push(args.friction);\n if (args.what_failed && args.what_failed !== args.friction) {\n frictionPoints.push(args.what_failed);\n }\n if (args.error_handling) frictionPoints.push(`Error handling: ${args.error_handling}`);\n if (args.service_switch) frictionPoints.push(`Service switch: ${args.service_switch}`);\n\n const providerMatch = args.apis_used?.match(/^(\\w+)/);\n const provider = providerMatch ? providerMatch[1].toLowerCase() : undefined;\n\n const endpointMatch = args.apis_used?.match(\n /(?:GET|POST|PUT|DELETE|PATCH)\\s+(\\/\\S+)/\n );\n const endpointPattern = endpointMatch ? endpointMatch[1] : undefined;\n\n return {\n event_type: \"feedback\",\n ts: Date.now() / 1000,\n source: \"journal\",\n worked,\n context: contextParts.join(\". \"),\n friction_points: frictionPoints.length > 0 ? frictionPoints : undefined,\n provider,\n endpoint_pattern: endpointPattern,\n framework_session_id: args.session_id || config.sessionId,\n agent_name: config.agentName,\n };\n}\n\nasync function handleReport(\n args: Record<string, any>,\n config: ServerConfig,\n reportCount: number\n) {\n // Validate required fields\n const missing: string[] = [];\n if (!args.task_goal) missing.push(\"task_goal\");\n if (!args.outcome) missing.push(\"outcome\");\n if (!args.apis_used) missing.push(\"apis_used\");\n if (missing.length > 0) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Missing required fields: ${missing.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n const validOutcomes = [\"success\", \"partial\", \"failure\", \"blocked\"];\n if (!validOutcomes.includes(args.outcome)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Invalid outcome \"${args.outcome}\". Must be one of: ${validOutcomes.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n const event = buildFeedbackEvent(args, config);\n const result = await postEvents(config, [event]);\n\n const responseLines = [\n `Report #${reportCount} submitted`,\n ` Accepted: ${result.accepted}, Errors: ${result.errors}`,\n ];\n\n if (result.quality_score != null) {\n responseLines.push(` Quality score: ${result.quality_score}/100`);\n }\n if (result.credits != null) {\n responseLines.push(` Credits earned: ${result.credits}`);\n }\n if (result.tip) {\n responseLines.push(` Tip: ${result.tip}`);\n }\n\n return {\n content: [{ type: \"text\" as const, text: responseLines.join(\"\\n\") }],\n };\n } catch (err: any) {\n console.error(\"canary_report error:\", err.message);\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Failed to submit report: ${err.message}`,\n },\n ],\n isError: true,\n };\n }\n}\n\n// ─── Main ────────────────────────────────────────────────────────────\n\nasync function main() {\n const config = parseArgs();\n let reportCount = 0;\n\n const server = new Server(\n { name: \"canary-journal\", version: \"0.2.0\" },\n {\n capabilities: { tools: {} },\n instructions:\n \"You MUST call canary_annotate before and after every HTTP request you make to an external API. \" +\n \"Before the call, note your intent — what you're about to do and why. \" +\n \"After the call, note what happened — status code, response structure, errors, and any quirks. \" +\n \"When a call fails, describe what you decided to do next in your annotation: \" +\n \"did you retry, try a different endpoint, or switch to a different service? \" +\n \"When your task is complete, call canary_report to compile your annotations into structured feedback. \" +\n \"Do not skip these steps — even failed requests are valuable data.\",\n }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [CANARY_ANNOTATE_TOOL, CANARY_REPORT_TOOL],\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const args = (request.params.arguments || {}) as Record<string, any>;\n\n switch (request.params.name) {\n case \"canary_annotate\":\n return handleAnnotate(args);\n\n case \"canary_report\":\n reportCount++;\n return handleReport(args, config, reportCount);\n\n default:\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Unknown tool: ${request.params.name}`,\n },\n ],\n isError: true,\n };\n }\n });\n\n const transport = new StdioServerTransport();\n console.error(\"Canary journal server v0.2.0 starting...\");\n console.error(` Endpoint: ${config.endpoint}`);\n console.error(` Session: ${config.sessionId || \"(auto)\"}`);\n console.error(` Agent: ${config.agentName || \"(unnamed)\"}`);\n console.error(` Tools: canary_annotate, canary_report`);\n await server.connect(transport);\n console.error(\"Canary journal server connected via stdio\");\n}\n\nmain().catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/journal/server.ts"],"sourcesContent":["/**\n * Canary MCP Journal Server — stdio transport.\n *\n * Tools:\n * canary_annotate — Save/read/list/clear local notes about API experiences.\n * canary_report — Submit structured feedback to the Canary backend.\n *\n * All logging goes to stderr to avoid corrupting the MCP protocol.\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n readFileSync,\n writeFileSync,\n mkdirSync,\n unlinkSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n// Redirect console to stderr to prevent stdout corruption\nconsole.log = (...args: any[]) => console.error(...args);\nconsole.info = (...args: any[]) => console.error(...args);\n\nconst FETCH_TIMEOUT_MS = 15_000;\n\n// ─── Annotations (local persistence) ────────────────────────────────\n\nfunction getAnnotationsDir(): string {\n const dir = join(homedir(), \".canary\", \"annotations\");\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\nfunction annotationPath(id: string): string {\n const safe = id.replace(/\\//g, \"--\");\n return join(getAnnotationsDir(), `${safe}.json`);\n}\n\nfunction readAnnotation(id: string): any | null {\n try {\n return JSON.parse(readFileSync(annotationPath(id), \"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeAnnotation(\n id: string,\n note: string\n): { id: string; note: string; updatedAt: string } {\n const data = { id, note, updatedAt: new Date().toISOString() };\n writeFileSync(annotationPath(id), JSON.stringify(data, null, 2));\n return data;\n}\n\nfunction clearAnnotation(id: string): boolean {\n try {\n unlinkSync(annotationPath(id));\n return true;\n } catch {\n return false;\n }\n}\n\nfunction listAnnotations(): any[] {\n const dir = getAnnotationsDir();\n try {\n return readdirSync(dir)\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => {\n try {\n return JSON.parse(readFileSync(join(dir, f), \"utf8\"));\n } catch {\n return null;\n }\n })\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n// ─── Tool definitions ────────────────────────────────────────────────\n\nconst CANARY_ANNOTATE_TOOL = {\n name: \"canary_annotate\",\n description:\n \"REQUIRED: Call this for every HTTP request you make to an external API. \" +\n \"Call it BEFORE the request with your intent (what you're about to do and why), \" +\n \"then call it AFTER with what happened (status, errors, and what you decided to do next). \" +\n \"Notes persist across sessions. Use provider/endpoint IDs like 'stripe/charges'.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n id: {\n type: \"string\",\n description:\n 'Identifier for the annotation (e.g. \"stripe/charges\", \"openai/chat\", \"github/repos\"). ' +\n \"Use provider/endpoint style.\",\n },\n intent: {\n type: \"string\",\n description:\n \"BEFORE the call: What are you about to do and why? \" +\n '(e.g. \"Fetching customer list from Stripe to find overdue invoices for the billing report\")',\n },\n note: {\n type: \"string\",\n description:\n \"AFTER the call: What happened? Include status code, response shape, errors, latency. \" +\n \"If the call failed, describe what you decided to do next — did you retry, \" +\n \"try a different endpoint, or switch to a different service entirely?\",\n },\n clear: {\n type: \"boolean\",\n description: \"Set true to delete the annotation for this id.\",\n },\n list: {\n type: \"boolean\",\n description: \"Set true to list all saved annotations.\",\n },\n },\n required: [],\n },\n};\n\nconst CANARY_REPORT_TOOL = {\n name: \"canary_report\",\n description:\n \"REQUIRED: Call this once when your task is complete to compile your \" +\n \"canary_annotate notes into structured feedback. Tell the full story: \" +\n \"what you intended to do, what actually happened, and every decision you made \" +\n \"along the way — especially when things went wrong. Your report earns credits \" +\n \"and improves API documentation for all agents.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n session_id: {\n type: \"string\",\n description:\n \"Session/task ID to link this report to HTTP telemetry. Pass the skill_execution_id or run ID.\",\n },\n intent: {\n type: \"string\",\n description:\n \"What was your plan going in? Describe your original approach before making any calls. \" +\n '(e.g. \"I planned to fetch Stripe charges, join them with customer emails, and generate a CSV billing report\")',\n },\n task_goal: {\n type: \"string\",\n description:\n 'What were you trying to accomplish? (e.g. \"Create a Stripe charge for $50 and send an SMS confirmation via Twilio\")',\n },\n outcome: {\n type: \"string\",\n enum: [\"success\", \"partial\", \"failure\", \"blocked\"],\n description: \"Did the task succeed?\",\n },\n apis_used: {\n type: \"string\",\n description:\n 'Which APIs did you call? List provider and key endpoints. (e.g. \"Stripe POST /v1/charges, Twilio POST /Messages.json\")',\n },\n what_worked: {\n type: \"string\",\n description:\n 'What went smoothly? Mention specific endpoints or features. (e.g. \"Stripe charge creation returned clear response with charge ID\")',\n },\n what_failed: {\n type: \"string\",\n description:\n 'What went wrong? Include error codes, status, and messages. (e.g. \"POST /v1/refunds returned 400: Charge already refunded\")',\n },\n error_handling: {\n type: \"string\",\n description:\n \"How did you handle each error? For every failure, describe the decision you made: \" +\n \"did you retry the same call, try a different endpoint on the same API, \" +\n \"or give up on that approach? \" +\n '(e.g. \"After /v1/charges returned 401, I tried /v1/payment_intents as an alternative but that also required auth. ' +\n 'I then tried the /v1/invoices endpoint hoping it had different permissions, but got the same 401.\")',\n },\n service_switch: {\n type: \"string\",\n description:\n \"If an API was completely blocked, did you switch to a different service or provider to accomplish the same goal? \" +\n \"Describe what you switched to and why. \" +\n '(e.g. \"Stripe was fully blocked so I switched to the PayPal Orders API to process the payment instead. ' +\n 'PayPal returned 200 and the order was created successfully.\")',\n },\n friction: {\n type: \"string\",\n description:\n \"The single biggest pain point. (e.g. \\\"Stripe charge object doesn't show refund status\\\")\",\n },\n suggestion: {\n type: \"string\",\n description:\n 'How could the API improve? (e.g. \"Add a refund_status field to the charge object\")',\n },\n },\n required: [\"task_goal\", \"outcome\", \"apis_used\"],\n },\n};\n\n// ─── Server config ───────────────────────────────────────────────────\n\ninterface ServerConfig {\n apiKey: string;\n endpoint?: string;\n sessionId?: string;\n agentName?: string;\n}\n\nfunction parseArgs(): ServerConfig {\n const args = process.argv.slice(2);\n let apiKey = process.env.CANARY_API_KEY || \"\";\n let endpoint = process.env.CANARY_ENDPOINT || \"http://localhost:8002\";\n let sessionId = process.env.CANARY_SESSION_ID;\n let agentName = process.env.CANARY_AGENT_NAME;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--api-key\" && args[i + 1]) apiKey = args[++i];\n else if (args[i] === \"--endpoint\" && args[i + 1]) endpoint = args[++i];\n else if (args[i] === \"--session-id\" && args[i + 1]) sessionId = args[++i];\n else if (args[i] === \"--agent-name\" && args[i + 1]) agentName = args[++i];\n else if (args[i].startsWith(\"--api-key=\"))\n apiKey = args[i].substring(\"--api-key=\".length);\n else if (args[i].startsWith(\"--endpoint=\"))\n endpoint = args[i].substring(\"--endpoint=\".length);\n else if (args[i].startsWith(\"--session-id=\"))\n sessionId = args[i].substring(\"--session-id=\".length);\n else if (args[i].startsWith(\"--agent-name=\"))\n agentName = args[i].substring(\"--agent-name=\".length);\n }\n\n if (!apiKey) {\n console.error(\"Error: --api-key or CANARY_API_KEY required\");\n process.exit(1);\n }\n\n return { apiKey, endpoint, sessionId, agentName };\n}\n\n// ─── Backend communication ───────────────────────────────────────────\n\nasync function postEvents(\n config: ServerConfig,\n events: any[]\n): Promise<any> {\n const url = `${config.endpoint}/v1/events`;\n const body = JSON.stringify({ events, sdk_version: \"0.1.0\" });\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n },\n body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`POST /v1/events failed: ${res.status} ${text}`);\n }\n\n return res.json();\n}\n\n// ─── Handlers ────────────────────────────────────────────────────────\n\nfunction handleAnnotate(args: Record<string, any>) {\n const { id, note, clear, list } = args;\n\n if (list) {\n const annotations = listAnnotations();\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n { annotations, total: annotations.length },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n if (!id) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"Missing required parameter: id. Provide a provider/endpoint id or use list mode.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n // Validate id\n if (id.length > 200) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error: \"ID too long (max 200 characters).\",\n }),\n },\n ],\n isError: true,\n };\n }\n if (!/^[a-zA-Z0-9._\\-\\/]+$/.test(id)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"ID contains invalid characters. Use alphanumeric, hyphens, underscores, dots, and slashes.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n if (clear) {\n const removed = clearAnnotation(id);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n status: removed ? \"cleared\" : \"not_found\",\n id,\n }),\n },\n ],\n };\n }\n\n if (note) {\n const saved = writeAnnotation(id, note);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"saved\", annotation: saved }, null, 2),\n },\n ],\n };\n }\n\n // Read mode\n const annotation = readAnnotation(id);\n if (annotation) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ annotation }, null, 2),\n },\n ],\n };\n }\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"no_annotation\", id }),\n },\n ],\n };\n}\n\nfunction buildFeedbackEvent(args: Record<string, any>, config: ServerConfig) {\n const outcome = args.outcome as string;\n const worked = outcome === \"success\" || outcome === \"partial\";\n\n const contextParts: string[] = [];\n if (args.intent) contextParts.push(`Intent: ${args.intent}`);\n contextParts.push(`Goal: ${args.task_goal}`);\n contextParts.push(`APIs: ${args.apis_used}`);\n contextParts.push(`Outcome: ${outcome}`);\n if (args.what_worked) contextParts.push(`Worked: ${args.what_worked}`);\n if (args.what_failed) contextParts.push(`Failed: ${args.what_failed}`);\n if (args.error_handling) contextParts.push(`Error Handling: ${args.error_handling}`);\n if (args.service_switch) contextParts.push(`Service Switch: ${args.service_switch}`);\n if (args.suggestion) contextParts.push(`Suggestion: ${args.suggestion}`);\n\n const frictionPoints: string[] = [];\n if (args.friction) frictionPoints.push(args.friction);\n if (args.what_failed && args.what_failed !== args.friction) {\n frictionPoints.push(args.what_failed);\n }\n if (args.error_handling) frictionPoints.push(`Error handling: ${args.error_handling}`);\n if (args.service_switch) frictionPoints.push(`Service switch: ${args.service_switch}`);\n\n const providerMatch = args.apis_used?.match(/^(\\w+)/);\n const provider = providerMatch ? providerMatch[1].toLowerCase() : undefined;\n\n const endpointMatch = args.apis_used?.match(\n /(?:GET|POST|PUT|DELETE|PATCH)\\s+(\\/\\S+)/\n );\n const endpointPattern = endpointMatch ? endpointMatch[1] : undefined;\n\n return {\n event_type: \"feedback\",\n ts: Date.now() / 1000,\n source: \"journal\",\n worked,\n context: contextParts.join(\". \"),\n friction_points: frictionPoints.length > 0 ? frictionPoints : undefined,\n provider,\n endpoint_pattern: endpointPattern,\n framework_session_id: args.session_id || config.sessionId,\n agent_name: config.agentName,\n };\n}\n\nasync function handleReport(\n args: Record<string, any>,\n config: ServerConfig,\n reportCount: number\n) {\n // Validate required fields\n const missing: string[] = [];\n if (!args.task_goal) missing.push(\"task_goal\");\n if (!args.outcome) missing.push(\"outcome\");\n if (!args.apis_used) missing.push(\"apis_used\");\n if (missing.length > 0) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Missing required fields: ${missing.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n const validOutcomes = [\"success\", \"partial\", \"failure\", \"blocked\"];\n if (!validOutcomes.includes(args.outcome)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Invalid outcome \"${args.outcome}\". Must be one of: ${validOutcomes.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n const event = buildFeedbackEvent(args, config);\n const result = await postEvents(config, [event]);\n\n const responseLines = [\n `Report #${reportCount} submitted`,\n ` Accepted: ${result.accepted}, Errors: ${result.errors}`,\n ];\n\n if (result.quality_score != null) {\n responseLines.push(` Quality score: ${result.quality_score}/100`);\n }\n if (result.credits != null) {\n responseLines.push(` Credits earned: ${result.credits}`);\n }\n if (result.tip) {\n responseLines.push(` Tip: ${result.tip}`);\n }\n\n return {\n content: [{ type: \"text\" as const, text: responseLines.join(\"\\n\") }],\n };\n } catch (err: any) {\n console.error(\"canary_report error:\", err.message);\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Failed to submit report: ${err.message}`,\n },\n ],\n isError: true,\n };\n }\n}\n\n// ─── Main ────────────────────────────────────────────────────────────\n\nasync function main() {\n const config = parseArgs();\n let reportCount = 0;\n\n const server = new Server(\n { name: \"canary-journal\", version: \"0.2.0\" },\n {\n capabilities: { tools: {} },\n instructions:\n \"You MUST call canary_annotate before and after every HTTP request you make to an external API. \" +\n \"Before the call, note your intent — what you're about to do and why. \" +\n \"After the call, note what happened — status code, response structure, errors, and any quirks. \" +\n \"When a call fails, describe what you decided to do next in your annotation: \" +\n \"did you retry, try a different endpoint, or switch to a different service? \" +\n \"When your task is complete, call canary_report to compile your annotations into structured feedback. \" +\n \"Do not skip these steps — even failed requests are valuable data.\",\n }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [CANARY_ANNOTATE_TOOL, CANARY_REPORT_TOOL],\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const args = (request.params.arguments || {}) as Record<string, any>;\n\n switch (request.params.name) {\n case \"canary_annotate\":\n return handleAnnotate(args);\n\n case \"canary_report\":\n reportCount++;\n return handleReport(args, config, reportCount);\n\n default:\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Unknown tool: ${request.params.name}`,\n },\n ],\n isError: true,\n };\n }\n });\n\n const transport = new StdioServerTransport();\n console.error(\"Canary journal server v0.2.0 starting...\");\n console.error(` Endpoint: ${config.endpoint}`);\n console.error(` Session: ${config.sessionId || \"(auto)\"}`);\n console.error(` Agent: ${config.agentName || \"(unnamed)\"}`);\n console.error(` Tools: canary_annotate, canary_report`);\n await server.connect(transport);\n console.error(\"Canary journal server connected via stdio\");\n}\n\nmain().catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
@@ -1 +1,2 @@
1
- #!/usr/bin/env node
1
+
2
+ export { }
@@ -1 +1,2 @@
1
- #!/usr/bin/env node
1
+
2
+ export { }
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- #!/usr/bin/env node
3
2
 
4
3
  // src/journal/server.ts
5
4
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/journal/server.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Canary MCP Journal Server — stdio transport.\n *\n * Tools:\n * canary_annotate — Save/read/list/clear local notes about API experiences.\n * canary_report — Submit structured feedback to the Canary backend.\n *\n * All logging goes to stderr to avoid corrupting the MCP protocol.\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n readFileSync,\n writeFileSync,\n mkdirSync,\n unlinkSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n// Redirect console to stderr to prevent stdout corruption\nconsole.log = (...args: any[]) => console.error(...args);\nconsole.info = (...args: any[]) => console.error(...args);\n\nconst FETCH_TIMEOUT_MS = 15_000;\n\n// ─── Annotations (local persistence) ────────────────────────────────\n\nfunction getAnnotationsDir(): string {\n const dir = join(homedir(), \".canary\", \"annotations\");\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\nfunction annotationPath(id: string): string {\n const safe = id.replace(/\\//g, \"--\");\n return join(getAnnotationsDir(), `${safe}.json`);\n}\n\nfunction readAnnotation(id: string): any | null {\n try {\n return JSON.parse(readFileSync(annotationPath(id), \"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeAnnotation(\n id: string,\n note: string\n): { id: string; note: string; updatedAt: string } {\n const data = { id, note, updatedAt: new Date().toISOString() };\n writeFileSync(annotationPath(id), JSON.stringify(data, null, 2));\n return data;\n}\n\nfunction clearAnnotation(id: string): boolean {\n try {\n unlinkSync(annotationPath(id));\n return true;\n } catch {\n return false;\n }\n}\n\nfunction listAnnotations(): any[] {\n const dir = getAnnotationsDir();\n try {\n return readdirSync(dir)\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => {\n try {\n return JSON.parse(readFileSync(join(dir, f), \"utf8\"));\n } catch {\n return null;\n }\n })\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n// ─── Tool definitions ────────────────────────────────────────────────\n\nconst CANARY_ANNOTATE_TOOL = {\n name: \"canary_annotate\",\n description:\n \"REQUIRED: Call this for every HTTP request you make to an external API. \" +\n \"Call it BEFORE the request with your intent (what you're about to do and why), \" +\n \"then call it AFTER with what happened (status, errors, and what you decided to do next). \" +\n \"Notes persist across sessions. Use provider/endpoint IDs like 'stripe/charges'.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n id: {\n type: \"string\",\n description:\n 'Identifier for the annotation (e.g. \"stripe/charges\", \"openai/chat\", \"github/repos\"). ' +\n \"Use provider/endpoint style.\",\n },\n intent: {\n type: \"string\",\n description:\n \"BEFORE the call: What are you about to do and why? \" +\n '(e.g. \"Fetching customer list from Stripe to find overdue invoices for the billing report\")',\n },\n note: {\n type: \"string\",\n description:\n \"AFTER the call: What happened? Include status code, response shape, errors, latency. \" +\n \"If the call failed, describe what you decided to do next — did you retry, \" +\n \"try a different endpoint, or switch to a different service entirely?\",\n },\n clear: {\n type: \"boolean\",\n description: \"Set true to delete the annotation for this id.\",\n },\n list: {\n type: \"boolean\",\n description: \"Set true to list all saved annotations.\",\n },\n },\n required: [],\n },\n};\n\nconst CANARY_REPORT_TOOL = {\n name: \"canary_report\",\n description:\n \"REQUIRED: Call this once when your task is complete to compile your \" +\n \"canary_annotate notes into structured feedback. Tell the full story: \" +\n \"what you intended to do, what actually happened, and every decision you made \" +\n \"along the way — especially when things went wrong. Your report earns credits \" +\n \"and improves API documentation for all agents.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n session_id: {\n type: \"string\",\n description:\n \"Session/task ID to link this report to HTTP telemetry. Pass the skill_execution_id or run ID.\",\n },\n intent: {\n type: \"string\",\n description:\n \"What was your plan going in? Describe your original approach before making any calls. \" +\n '(e.g. \"I planned to fetch Stripe charges, join them with customer emails, and generate a CSV billing report\")',\n },\n task_goal: {\n type: \"string\",\n description:\n 'What were you trying to accomplish? (e.g. \"Create a Stripe charge for $50 and send an SMS confirmation via Twilio\")',\n },\n outcome: {\n type: \"string\",\n enum: [\"success\", \"partial\", \"failure\", \"blocked\"],\n description: \"Did the task succeed?\",\n },\n apis_used: {\n type: \"string\",\n description:\n 'Which APIs did you call? List provider and key endpoints. (e.g. \"Stripe POST /v1/charges, Twilio POST /Messages.json\")',\n },\n what_worked: {\n type: \"string\",\n description:\n 'What went smoothly? Mention specific endpoints or features. (e.g. \"Stripe charge creation returned clear response with charge ID\")',\n },\n what_failed: {\n type: \"string\",\n description:\n 'What went wrong? Include error codes, status, and messages. (e.g. \"POST /v1/refunds returned 400: Charge already refunded\")',\n },\n error_handling: {\n type: \"string\",\n description:\n \"How did you handle each error? For every failure, describe the decision you made: \" +\n \"did you retry the same call, try a different endpoint on the same API, \" +\n \"or give up on that approach? \" +\n '(e.g. \"After /v1/charges returned 401, I tried /v1/payment_intents as an alternative but that also required auth. ' +\n 'I then tried the /v1/invoices endpoint hoping it had different permissions, but got the same 401.\")',\n },\n service_switch: {\n type: \"string\",\n description:\n \"If an API was completely blocked, did you switch to a different service or provider to accomplish the same goal? \" +\n \"Describe what you switched to and why. \" +\n '(e.g. \"Stripe was fully blocked so I switched to the PayPal Orders API to process the payment instead. ' +\n 'PayPal returned 200 and the order was created successfully.\")',\n },\n friction: {\n type: \"string\",\n description:\n \"The single biggest pain point. (e.g. \\\"Stripe charge object doesn't show refund status\\\")\",\n },\n suggestion: {\n type: \"string\",\n description:\n 'How could the API improve? (e.g. \"Add a refund_status field to the charge object\")',\n },\n },\n required: [\"task_goal\", \"outcome\", \"apis_used\"],\n },\n};\n\n// ─── Server config ───────────────────────────────────────────────────\n\ninterface ServerConfig {\n apiKey: string;\n endpoint?: string;\n sessionId?: string;\n agentName?: string;\n}\n\nfunction parseArgs(): ServerConfig {\n const args = process.argv.slice(2);\n let apiKey = process.env.CANARY_API_KEY || \"\";\n let endpoint = process.env.CANARY_ENDPOINT || \"http://localhost:8002\";\n let sessionId = process.env.CANARY_SESSION_ID;\n let agentName = process.env.CANARY_AGENT_NAME;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--api-key\" && args[i + 1]) apiKey = args[++i];\n else if (args[i] === \"--endpoint\" && args[i + 1]) endpoint = args[++i];\n else if (args[i] === \"--session-id\" && args[i + 1]) sessionId = args[++i];\n else if (args[i] === \"--agent-name\" && args[i + 1]) agentName = args[++i];\n else if (args[i].startsWith(\"--api-key=\"))\n apiKey = args[i].substring(\"--api-key=\".length);\n else if (args[i].startsWith(\"--endpoint=\"))\n endpoint = args[i].substring(\"--endpoint=\".length);\n else if (args[i].startsWith(\"--session-id=\"))\n sessionId = args[i].substring(\"--session-id=\".length);\n else if (args[i].startsWith(\"--agent-name=\"))\n agentName = args[i].substring(\"--agent-name=\".length);\n }\n\n if (!apiKey) {\n console.error(\"Error: --api-key or CANARY_API_KEY required\");\n process.exit(1);\n }\n\n return { apiKey, endpoint, sessionId, agentName };\n}\n\n// ─── Backend communication ───────────────────────────────────────────\n\nasync function postEvents(\n config: ServerConfig,\n events: any[]\n): Promise<any> {\n const url = `${config.endpoint}/v1/events`;\n const body = JSON.stringify({ events, sdk_version: \"0.1.0\" });\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n },\n body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`POST /v1/events failed: ${res.status} ${text}`);\n }\n\n return res.json();\n}\n\n// ─── Handlers ────────────────────────────────────────────────────────\n\nfunction handleAnnotate(args: Record<string, any>) {\n const { id, note, clear, list } = args;\n\n if (list) {\n const annotations = listAnnotations();\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n { annotations, total: annotations.length },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n if (!id) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"Missing required parameter: id. Provide a provider/endpoint id or use list mode.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n // Validate id\n if (id.length > 200) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error: \"ID too long (max 200 characters).\",\n }),\n },\n ],\n isError: true,\n };\n }\n if (!/^[a-zA-Z0-9._\\-\\/]+$/.test(id)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"ID contains invalid characters. Use alphanumeric, hyphens, underscores, dots, and slashes.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n if (clear) {\n const removed = clearAnnotation(id);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n status: removed ? \"cleared\" : \"not_found\",\n id,\n }),\n },\n ],\n };\n }\n\n if (note) {\n const saved = writeAnnotation(id, note);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"saved\", annotation: saved }, null, 2),\n },\n ],\n };\n }\n\n // Read mode\n const annotation = readAnnotation(id);\n if (annotation) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ annotation }, null, 2),\n },\n ],\n };\n }\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"no_annotation\", id }),\n },\n ],\n };\n}\n\nfunction buildFeedbackEvent(args: Record<string, any>, config: ServerConfig) {\n const outcome = args.outcome as string;\n const worked = outcome === \"success\" || outcome === \"partial\";\n\n const contextParts: string[] = [];\n if (args.intent) contextParts.push(`Intent: ${args.intent}`);\n contextParts.push(`Goal: ${args.task_goal}`);\n contextParts.push(`APIs: ${args.apis_used}`);\n contextParts.push(`Outcome: ${outcome}`);\n if (args.what_worked) contextParts.push(`Worked: ${args.what_worked}`);\n if (args.what_failed) contextParts.push(`Failed: ${args.what_failed}`);\n if (args.error_handling) contextParts.push(`Error Handling: ${args.error_handling}`);\n if (args.service_switch) contextParts.push(`Service Switch: ${args.service_switch}`);\n if (args.suggestion) contextParts.push(`Suggestion: ${args.suggestion}`);\n\n const frictionPoints: string[] = [];\n if (args.friction) frictionPoints.push(args.friction);\n if (args.what_failed && args.what_failed !== args.friction) {\n frictionPoints.push(args.what_failed);\n }\n if (args.error_handling) frictionPoints.push(`Error handling: ${args.error_handling}`);\n if (args.service_switch) frictionPoints.push(`Service switch: ${args.service_switch}`);\n\n const providerMatch = args.apis_used?.match(/^(\\w+)/);\n const provider = providerMatch ? providerMatch[1].toLowerCase() : undefined;\n\n const endpointMatch = args.apis_used?.match(\n /(?:GET|POST|PUT|DELETE|PATCH)\\s+(\\/\\S+)/\n );\n const endpointPattern = endpointMatch ? endpointMatch[1] : undefined;\n\n return {\n event_type: \"feedback\",\n ts: Date.now() / 1000,\n source: \"journal\",\n worked,\n context: contextParts.join(\". \"),\n friction_points: frictionPoints.length > 0 ? frictionPoints : undefined,\n provider,\n endpoint_pattern: endpointPattern,\n framework_session_id: args.session_id || config.sessionId,\n agent_name: config.agentName,\n };\n}\n\nasync function handleReport(\n args: Record<string, any>,\n config: ServerConfig,\n reportCount: number\n) {\n // Validate required fields\n const missing: string[] = [];\n if (!args.task_goal) missing.push(\"task_goal\");\n if (!args.outcome) missing.push(\"outcome\");\n if (!args.apis_used) missing.push(\"apis_used\");\n if (missing.length > 0) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Missing required fields: ${missing.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n const validOutcomes = [\"success\", \"partial\", \"failure\", \"blocked\"];\n if (!validOutcomes.includes(args.outcome)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Invalid outcome \"${args.outcome}\". Must be one of: ${validOutcomes.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n const event = buildFeedbackEvent(args, config);\n const result = await postEvents(config, [event]);\n\n const responseLines = [\n `Report #${reportCount} submitted`,\n ` Accepted: ${result.accepted}, Errors: ${result.errors}`,\n ];\n\n if (result.quality_score != null) {\n responseLines.push(` Quality score: ${result.quality_score}/100`);\n }\n if (result.credits != null) {\n responseLines.push(` Credits earned: ${result.credits}`);\n }\n if (result.tip) {\n responseLines.push(` Tip: ${result.tip}`);\n }\n\n return {\n content: [{ type: \"text\" as const, text: responseLines.join(\"\\n\") }],\n };\n } catch (err: any) {\n console.error(\"canary_report error:\", err.message);\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Failed to submit report: ${err.message}`,\n },\n ],\n isError: true,\n };\n }\n}\n\n// ─── Main ────────────────────────────────────────────────────────────\n\nasync function main() {\n const config = parseArgs();\n let reportCount = 0;\n\n const server = new Server(\n { name: \"canary-journal\", version: \"0.2.0\" },\n {\n capabilities: { tools: {} },\n instructions:\n \"You MUST call canary_annotate before and after every HTTP request you make to an external API. \" +\n \"Before the call, note your intent — what you're about to do and why. \" +\n \"After the call, note what happened — status code, response structure, errors, and any quirks. \" +\n \"When a call fails, describe what you decided to do next in your annotation: \" +\n \"did you retry, try a different endpoint, or switch to a different service? \" +\n \"When your task is complete, call canary_report to compile your annotations into structured feedback. \" +\n \"Do not skip these steps — even failed requests are valuable data.\",\n }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [CANARY_ANNOTATE_TOOL, CANARY_REPORT_TOOL],\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const args = (request.params.arguments || {}) as Record<string, any>;\n\n switch (request.params.name) {\n case \"canary_annotate\":\n return handleAnnotate(args);\n\n case \"canary_report\":\n reportCount++;\n return handleReport(args, config, reportCount);\n\n default:\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Unknown tool: ${request.params.name}`,\n },\n ],\n isError: true,\n };\n }\n });\n\n const transport = new StdioServerTransport();\n console.error(\"Canary journal server v0.2.0 starting...\");\n console.error(` Endpoint: ${config.endpoint}`);\n console.error(` Session: ${config.sessionId || \"(auto)\"}`);\n console.error(` Agent: ${config.agentName || \"(unnamed)\"}`);\n console.error(` Tools: canary_annotate, canary_report`);\n await server.connect(transport);\n console.error(\"Canary journal server connected via stdio\");\n}\n\nmain().catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/journal/server.ts"],"sourcesContent":["/**\n * Canary MCP Journal Server — stdio transport.\n *\n * Tools:\n * canary_annotate — Save/read/list/clear local notes about API experiences.\n * canary_report — Submit structured feedback to the Canary backend.\n *\n * All logging goes to stderr to avoid corrupting the MCP protocol.\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n readFileSync,\n writeFileSync,\n mkdirSync,\n unlinkSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n// Redirect console to stderr to prevent stdout corruption\nconsole.log = (...args: any[]) => console.error(...args);\nconsole.info = (...args: any[]) => console.error(...args);\n\nconst FETCH_TIMEOUT_MS = 15_000;\n\n// ─── Annotations (local persistence) ────────────────────────────────\n\nfunction getAnnotationsDir(): string {\n const dir = join(homedir(), \".canary\", \"annotations\");\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\nfunction annotationPath(id: string): string {\n const safe = id.replace(/\\//g, \"--\");\n return join(getAnnotationsDir(), `${safe}.json`);\n}\n\nfunction readAnnotation(id: string): any | null {\n try {\n return JSON.parse(readFileSync(annotationPath(id), \"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeAnnotation(\n id: string,\n note: string\n): { id: string; note: string; updatedAt: string } {\n const data = { id, note, updatedAt: new Date().toISOString() };\n writeFileSync(annotationPath(id), JSON.stringify(data, null, 2));\n return data;\n}\n\nfunction clearAnnotation(id: string): boolean {\n try {\n unlinkSync(annotationPath(id));\n return true;\n } catch {\n return false;\n }\n}\n\nfunction listAnnotations(): any[] {\n const dir = getAnnotationsDir();\n try {\n return readdirSync(dir)\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => {\n try {\n return JSON.parse(readFileSync(join(dir, f), \"utf8\"));\n } catch {\n return null;\n }\n })\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n// ─── Tool definitions ────────────────────────────────────────────────\n\nconst CANARY_ANNOTATE_TOOL = {\n name: \"canary_annotate\",\n description:\n \"REQUIRED: Call this for every HTTP request you make to an external API. \" +\n \"Call it BEFORE the request with your intent (what you're about to do and why), \" +\n \"then call it AFTER with what happened (status, errors, and what you decided to do next). \" +\n \"Notes persist across sessions. Use provider/endpoint IDs like 'stripe/charges'.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n id: {\n type: \"string\",\n description:\n 'Identifier for the annotation (e.g. \"stripe/charges\", \"openai/chat\", \"github/repos\"). ' +\n \"Use provider/endpoint style.\",\n },\n intent: {\n type: \"string\",\n description:\n \"BEFORE the call: What are you about to do and why? \" +\n '(e.g. \"Fetching customer list from Stripe to find overdue invoices for the billing report\")',\n },\n note: {\n type: \"string\",\n description:\n \"AFTER the call: What happened? Include status code, response shape, errors, latency. \" +\n \"If the call failed, describe what you decided to do next — did you retry, \" +\n \"try a different endpoint, or switch to a different service entirely?\",\n },\n clear: {\n type: \"boolean\",\n description: \"Set true to delete the annotation for this id.\",\n },\n list: {\n type: \"boolean\",\n description: \"Set true to list all saved annotations.\",\n },\n },\n required: [],\n },\n};\n\nconst CANARY_REPORT_TOOL = {\n name: \"canary_report\",\n description:\n \"REQUIRED: Call this once when your task is complete to compile your \" +\n \"canary_annotate notes into structured feedback. Tell the full story: \" +\n \"what you intended to do, what actually happened, and every decision you made \" +\n \"along the way — especially when things went wrong. Your report earns credits \" +\n \"and improves API documentation for all agents.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n session_id: {\n type: \"string\",\n description:\n \"Session/task ID to link this report to HTTP telemetry. Pass the skill_execution_id or run ID.\",\n },\n intent: {\n type: \"string\",\n description:\n \"What was your plan going in? Describe your original approach before making any calls. \" +\n '(e.g. \"I planned to fetch Stripe charges, join them with customer emails, and generate a CSV billing report\")',\n },\n task_goal: {\n type: \"string\",\n description:\n 'What were you trying to accomplish? (e.g. \"Create a Stripe charge for $50 and send an SMS confirmation via Twilio\")',\n },\n outcome: {\n type: \"string\",\n enum: [\"success\", \"partial\", \"failure\", \"blocked\"],\n description: \"Did the task succeed?\",\n },\n apis_used: {\n type: \"string\",\n description:\n 'Which APIs did you call? List provider and key endpoints. (e.g. \"Stripe POST /v1/charges, Twilio POST /Messages.json\")',\n },\n what_worked: {\n type: \"string\",\n description:\n 'What went smoothly? Mention specific endpoints or features. (e.g. \"Stripe charge creation returned clear response with charge ID\")',\n },\n what_failed: {\n type: \"string\",\n description:\n 'What went wrong? Include error codes, status, and messages. (e.g. \"POST /v1/refunds returned 400: Charge already refunded\")',\n },\n error_handling: {\n type: \"string\",\n description:\n \"How did you handle each error? For every failure, describe the decision you made: \" +\n \"did you retry the same call, try a different endpoint on the same API, \" +\n \"or give up on that approach? \" +\n '(e.g. \"After /v1/charges returned 401, I tried /v1/payment_intents as an alternative but that also required auth. ' +\n 'I then tried the /v1/invoices endpoint hoping it had different permissions, but got the same 401.\")',\n },\n service_switch: {\n type: \"string\",\n description:\n \"If an API was completely blocked, did you switch to a different service or provider to accomplish the same goal? \" +\n \"Describe what you switched to and why. \" +\n '(e.g. \"Stripe was fully blocked so I switched to the PayPal Orders API to process the payment instead. ' +\n 'PayPal returned 200 and the order was created successfully.\")',\n },\n friction: {\n type: \"string\",\n description:\n \"The single biggest pain point. (e.g. \\\"Stripe charge object doesn't show refund status\\\")\",\n },\n suggestion: {\n type: \"string\",\n description:\n 'How could the API improve? (e.g. \"Add a refund_status field to the charge object\")',\n },\n },\n required: [\"task_goal\", \"outcome\", \"apis_used\"],\n },\n};\n\n// ─── Server config ───────────────────────────────────────────────────\n\ninterface ServerConfig {\n apiKey: string;\n endpoint?: string;\n sessionId?: string;\n agentName?: string;\n}\n\nfunction parseArgs(): ServerConfig {\n const args = process.argv.slice(2);\n let apiKey = process.env.CANARY_API_KEY || \"\";\n let endpoint = process.env.CANARY_ENDPOINT || \"http://localhost:8002\";\n let sessionId = process.env.CANARY_SESSION_ID;\n let agentName = process.env.CANARY_AGENT_NAME;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--api-key\" && args[i + 1]) apiKey = args[++i];\n else if (args[i] === \"--endpoint\" && args[i + 1]) endpoint = args[++i];\n else if (args[i] === \"--session-id\" && args[i + 1]) sessionId = args[++i];\n else if (args[i] === \"--agent-name\" && args[i + 1]) agentName = args[++i];\n else if (args[i].startsWith(\"--api-key=\"))\n apiKey = args[i].substring(\"--api-key=\".length);\n else if (args[i].startsWith(\"--endpoint=\"))\n endpoint = args[i].substring(\"--endpoint=\".length);\n else if (args[i].startsWith(\"--session-id=\"))\n sessionId = args[i].substring(\"--session-id=\".length);\n else if (args[i].startsWith(\"--agent-name=\"))\n agentName = args[i].substring(\"--agent-name=\".length);\n }\n\n if (!apiKey) {\n console.error(\"Error: --api-key or CANARY_API_KEY required\");\n process.exit(1);\n }\n\n return { apiKey, endpoint, sessionId, agentName };\n}\n\n// ─── Backend communication ───────────────────────────────────────────\n\nasync function postEvents(\n config: ServerConfig,\n events: any[]\n): Promise<any> {\n const url = `${config.endpoint}/v1/events`;\n const body = JSON.stringify({ events, sdk_version: \"0.1.0\" });\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n },\n body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`POST /v1/events failed: ${res.status} ${text}`);\n }\n\n return res.json();\n}\n\n// ─── Handlers ────────────────────────────────────────────────────────\n\nfunction handleAnnotate(args: Record<string, any>) {\n const { id, note, clear, list } = args;\n\n if (list) {\n const annotations = listAnnotations();\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n { annotations, total: annotations.length },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n if (!id) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"Missing required parameter: id. Provide a provider/endpoint id or use list mode.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n // Validate id\n if (id.length > 200) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error: \"ID too long (max 200 characters).\",\n }),\n },\n ],\n isError: true,\n };\n }\n if (!/^[a-zA-Z0-9._\\-\\/]+$/.test(id)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n error:\n \"ID contains invalid characters. Use alphanumeric, hyphens, underscores, dots, and slashes.\",\n }),\n },\n ],\n isError: true,\n };\n }\n\n if (clear) {\n const removed = clearAnnotation(id);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({\n status: removed ? \"cleared\" : \"not_found\",\n id,\n }),\n },\n ],\n };\n }\n\n if (note) {\n const saved = writeAnnotation(id, note);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"saved\", annotation: saved }, null, 2),\n },\n ],\n };\n }\n\n // Read mode\n const annotation = readAnnotation(id);\n if (annotation) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ annotation }, null, 2),\n },\n ],\n };\n }\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ status: \"no_annotation\", id }),\n },\n ],\n };\n}\n\nfunction buildFeedbackEvent(args: Record<string, any>, config: ServerConfig) {\n const outcome = args.outcome as string;\n const worked = outcome === \"success\" || outcome === \"partial\";\n\n const contextParts: string[] = [];\n if (args.intent) contextParts.push(`Intent: ${args.intent}`);\n contextParts.push(`Goal: ${args.task_goal}`);\n contextParts.push(`APIs: ${args.apis_used}`);\n contextParts.push(`Outcome: ${outcome}`);\n if (args.what_worked) contextParts.push(`Worked: ${args.what_worked}`);\n if (args.what_failed) contextParts.push(`Failed: ${args.what_failed}`);\n if (args.error_handling) contextParts.push(`Error Handling: ${args.error_handling}`);\n if (args.service_switch) contextParts.push(`Service Switch: ${args.service_switch}`);\n if (args.suggestion) contextParts.push(`Suggestion: ${args.suggestion}`);\n\n const frictionPoints: string[] = [];\n if (args.friction) frictionPoints.push(args.friction);\n if (args.what_failed && args.what_failed !== args.friction) {\n frictionPoints.push(args.what_failed);\n }\n if (args.error_handling) frictionPoints.push(`Error handling: ${args.error_handling}`);\n if (args.service_switch) frictionPoints.push(`Service switch: ${args.service_switch}`);\n\n const providerMatch = args.apis_used?.match(/^(\\w+)/);\n const provider = providerMatch ? providerMatch[1].toLowerCase() : undefined;\n\n const endpointMatch = args.apis_used?.match(\n /(?:GET|POST|PUT|DELETE|PATCH)\\s+(\\/\\S+)/\n );\n const endpointPattern = endpointMatch ? endpointMatch[1] : undefined;\n\n return {\n event_type: \"feedback\",\n ts: Date.now() / 1000,\n source: \"journal\",\n worked,\n context: contextParts.join(\". \"),\n friction_points: frictionPoints.length > 0 ? frictionPoints : undefined,\n provider,\n endpoint_pattern: endpointPattern,\n framework_session_id: args.session_id || config.sessionId,\n agent_name: config.agentName,\n };\n}\n\nasync function handleReport(\n args: Record<string, any>,\n config: ServerConfig,\n reportCount: number\n) {\n // Validate required fields\n const missing: string[] = [];\n if (!args.task_goal) missing.push(\"task_goal\");\n if (!args.outcome) missing.push(\"outcome\");\n if (!args.apis_used) missing.push(\"apis_used\");\n if (missing.length > 0) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Missing required fields: ${missing.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n const validOutcomes = [\"success\", \"partial\", \"failure\", \"blocked\"];\n if (!validOutcomes.includes(args.outcome)) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Invalid outcome \"${args.outcome}\". Must be one of: ${validOutcomes.join(\", \")}`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n const event = buildFeedbackEvent(args, config);\n const result = await postEvents(config, [event]);\n\n const responseLines = [\n `Report #${reportCount} submitted`,\n ` Accepted: ${result.accepted}, Errors: ${result.errors}`,\n ];\n\n if (result.quality_score != null) {\n responseLines.push(` Quality score: ${result.quality_score}/100`);\n }\n if (result.credits != null) {\n responseLines.push(` Credits earned: ${result.credits}`);\n }\n if (result.tip) {\n responseLines.push(` Tip: ${result.tip}`);\n }\n\n return {\n content: [{ type: \"text\" as const, text: responseLines.join(\"\\n\") }],\n };\n } catch (err: any) {\n console.error(\"canary_report error:\", err.message);\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Failed to submit report: ${err.message}`,\n },\n ],\n isError: true,\n };\n }\n}\n\n// ─── Main ────────────────────────────────────────────────────────────\n\nasync function main() {\n const config = parseArgs();\n let reportCount = 0;\n\n const server = new Server(\n { name: \"canary-journal\", version: \"0.2.0\" },\n {\n capabilities: { tools: {} },\n instructions:\n \"You MUST call canary_annotate before and after every HTTP request you make to an external API. \" +\n \"Before the call, note your intent — what you're about to do and why. \" +\n \"After the call, note what happened — status code, response structure, errors, and any quirks. \" +\n \"When a call fails, describe what you decided to do next in your annotation: \" +\n \"did you retry, try a different endpoint, or switch to a different service? \" +\n \"When your task is complete, call canary_report to compile your annotations into structured feedback. \" +\n \"Do not skip these steps — even failed requests are valuable data.\",\n }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [CANARY_ANNOTATE_TOOL, CANARY_REPORT_TOOL],\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const args = (request.params.arguments || {}) as Record<string, any>;\n\n switch (request.params.name) {\n case \"canary_annotate\":\n return handleAnnotate(args);\n\n case \"canary_report\":\n reportCount++;\n return handleReport(args, config, reportCount);\n\n default:\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Unknown tool: ${request.params.name}`,\n },\n ],\n isError: true,\n };\n }\n });\n\n const transport = new StdioServerTransport();\n console.error(\"Canary journal server v0.2.0 starting...\");\n console.error(` Endpoint: ${config.endpoint}`);\n console.error(` Session: ${config.sessionId || \"(auto)\"}`);\n console.error(` Agent: ${config.agentName || \"(unnamed)\"}`);\n console.error(` Tools: canary_annotate, canary_report`);\n await server.connect(transport);\n console.error(\"Canary journal server connected via stdio\");\n}\n\nmain().catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canary-agent",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Canary API observability SDK for Node.js — zero-dependency HTTP telemetry and structured feedback for AI agents",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -39,7 +39,7 @@
39
39
  ],
40
40
  "repository": {
41
41
  "type": "git",
42
- "url": "https://github.com/vikasvs/canary.git",
42
+ "url": "git+https://github.com/vikasvs/canary.git",
43
43
  "directory": "canary"
44
44
  },
45
45
  "homepage": "https://github.com/vikasvs/canary/tree/main/canary#readme",
@@ -55,8 +55,8 @@
55
55
  "prepublishOnly": "npm run build && npm test && npm run test:dist"
56
56
  },
57
57
  "bin": {
58
- "canary-journal": "./dist/journal/server.js",
59
- "canary-agent": "./dist/journal/server.js"
58
+ "canary-journal": "dist/journal/server.js",
59
+ "canary-agent": "dist/journal/server.js"
60
60
  },
61
61
  "dependencies": {
62
62
  "@modelcontextprotocol/sdk": "^1.0.0"