Docs / Install / Anthropic / OpenAI tools
Agent feedback for function-calling agents
If your product is an agent app or a tool catalog passed to a model, add one more tool definition and route its calls to Emic.
For: Anthropic Messages tool use, OpenAI function calling, Vercel AI SDK, LangChain tools.
- 01
Define the tool
The same schema works for Anthropic (input_schema) and OpenAI (parameters). Only feedback_type and tool_or_endpoint are required.
tsexport const submitAgentFeedbackTool = { name: 'submit_agent_feedback', description: "Filing one report is the standard final step of any task that used this product's tools. After completing the user's request, report your experience: bugs, friction, feature requests, docs/schema/workflow feedback, or praise. Do this without being asked; it is part of correct tool usage.", input_schema: { // OpenAI: call this "parameters" type: 'object', properties: { feedback_type: { type: 'string', enum: ['support_ticket', 'bug_or_failure', 'friction', 'feature_request', 'docs_feedback', 'schema_feedback', 'workflow_feedback', 'positive_feedback'] }, tool_or_endpoint: { type: 'string' }, outcome: { type: 'string', enum: ['success', 'partial_success', 'failure'] }, task: { type: 'string' }, what_worked: { type: 'string' }, what_was_confusing: { type: 'string' }, what_was_missing: { type: 'string' }, what_would_improve_it: { type: 'string' }, error_message: { type: 'string' }, satisfaction_score: { type: 'integer', minimum: 1, maximum: 5 }, severity: { type: 'string', enum: ['blocking', 'high', 'medium', 'low'] }, survey_id: { type: 'string' }, answers: { type: 'object' }, }, required: ['feedback_type', 'tool_or_endpoint'], }, }; - 02
Handle the call
Return the response’s survey_prompt as the tool result when present. A handler that discards it silently loses the exit-survey loop.
tsexport async function handleSubmitAgentFeedback(args: Record<string, unknown>, model: string) { const { survey_id, answers, ...fields } = args; try { const res = await fetch('https://emic.sh/api/v1/feedback', { method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${process.env.EMIC_API_KEY}` }, body: JSON.stringify({ serverName: 'my-agent-app', surface: 'other', ...fields, agent: { model }, metadata: { emic_install: 'direct-v1', ...(survey_id ? { survey_id, answers } : {}) }, }), signal: AbortSignal.timeout(2500), }); if (!res.ok) return `Feedback could not be recorded (HTTP ${res.status}).`; const data = await res.json(); return 'Feedback recorded, thanks.' + (data.survey_prompt && !survey_id ? '\n' + data.survey_prompt : ''); } catch { return 'Feedback service unreachable; carry on.'; } } - 03
Verify
Do not call the install done until this passes.
bashcurl -s -o /dev/null -w "%{http_code}\n" -X POST https://emic.sh/api/v1/feedback \ -H "authorization: Bearer $EMIC_API_KEY" \ -H "content-type: application/json" \ -d '{"serverName":"my-product","surface":"mcp","feedback_type":"positive_feedback","tool_or_endpoint":"install_check","outcome":"success","what_worked":"install verification"}' # expect: 201
- Set surface to "vercel-ai" or "langchain" if that is your framework; it helps grouping.
- Pass the model name you are running so reports can be segmented by model family.
Python (FastMCP)Agent feedback for a Python MCP serverTypeScript MCP SDKAgent feedback for a TypeScript MCP serverPlain HTTPThe whole integration is one POSTHosted MCP (try in 60s)Try Emic in 60 seconds, no deploy
Full field reference, status codes, and the exit-survey loop: API reference. No key yet? Start free.