Skip to main content
Glama
TOOL-PATTERNS.md5.97 kB
# OpenRouter Agents MCP Server - Tool Patterns & Gotchas This document captures learnings, patterns, and common issues when using the MCP server tools. ## Known Issues & Fixes ### 1. `sample_message` - Fixed in commit **Issue**: Calling `samplingHandler.handleSampling()` but method is `createMessage()` **Fix**: Changed to `samplingHandler.createMessage({ params: p }, ex)` **Status**: Code fixed, requires server restart ### 2. `get_report` - Parameter Normalization Enhanced **Issue**: `reportId` coming through as `undefined` **Fix**: Enhanced parameter normalization to handle: - `{reportId: "2"}` - standard - `{reportId: 2}` - number (auto-converted to string) - `{id: "2"}` - alternate key - `{report_id: "2"}` - snake_case - `"2"` - raw string input **Status**: Code fixed, requires server restart --- ## Tool Input Patterns ### Pattern: Freeform to Structured The server's `normalizeParamsForTool()` function converts loose inputs to structured params: ```javascript // All of these work for calc: {"expr": "2+2"} // Structured (preferred) "2+2" // Raw string {"random_string": "2+2"} // Legacy format ``` ### Pattern: Mode Detection for `retrieve` ```javascript // Auto-detects SQL mode: {"sql": "SELECT * FROM reports"} // mode becomes "sql" "SELECT * FROM reports" // also detected as SQL // Auto-detects index mode: {"query": "find research"} // mode becomes "index" "find research" // also index mode ``` ### Pattern: Alias Resolution ```javascript // These are equivalent: {"query": "topic", "costPreference": "low"} {"q": "topic", "cost": "low"} ``` --- ## Tool-Specific Gotchas ### `research` / `conduct_research` - **Gotcha**: Without `query` parameter, runs with empty/default query - **Solution**: Always provide explicit `query` - **Gotcha**: `async: true` returns job_id, `async: false` streams - **Pattern**: Use async for >30s expected research ### `job_status` / `get_job_status` - **Gotcha**: Jobs have 1-hour TTL, then expire from memory - **Pattern**: Extract report ID immediately when job completes - **Pattern**: Use `since_event_id` for incremental polling ### `get_report` / `get_report_content` - **Gotcha**: Requires string reportId (now auto-converted) - **Gotcha**: `mode: "summary"` requires semantic embedding - **Pattern**: Use `mode: "full"` for complete content ### `search` - **Gotcha**: Requires `q` parameter (not optional) - **Pattern**: Use `scope: "reports"` for research-only results - **Pattern**: `k` defaults to 10, increase for broader search ### `query` - **Gotcha**: Only SELECT statements allowed - **Gotcha**: Params use PostgreSQL $1, $2 placeholders - **Pattern**: Use `explain: true` for natural language summary ### `calc` - **Gotcha**: Requires `expr` parameter explicitly - **Gotcha**: Error message "Invalid characters" when expr missing - **Supported**: +, -, *, /, ^, (), decimals ### `date_time` - **Gotcha**: Format parameter is optional - **Pattern**: `"iso"`, `"rfc"`, `"epoch"`, `"unix"` (same as epoch) --- ## Workflow Gotchas ### Async Research Lifecycle ``` research → job_id ↓ job_status (poll) → status: running/completed/failed ↓ When completed: Parse result for "Report ID: X" ↓ get_report {reportId: "X"} ``` **Gotcha**: Report ID is in the result message string, needs parsing ### Search Before Research ``` search {q: "topic"} → Check existing knowledge ↓ If found: get_report for details If not found: conduct_research for new synthesis ``` **Pattern**: Avoid redundant research by checking KB first --- ## Parameter Type Coercion The server attempts to coerce types: | Parameter | Input | Coerced To | |-----------|-------|------------| | reportId | `2` (number) | `"2"` (string) | | limit | `"10"` (string) | `10` (number) | | async | `"true"` (string) | `true` (boolean) | | k | `"5"` (string) | `5` (number) | --- ## Error Recovery Patterns ### Job Not Found ```javascript // Error: "Job unknown: Not found or invalid job ID" // Recovery: 1. Check task_list for valid job IDs 2. Jobs expire after 1 hour 3. Use correct job_id format: "job_xxx_yyy" ``` ### Report Not Found ```javascript // Error: "Report ID X not found" // Recovery: 1. Check history for valid report IDs 2. Ensure reportId is string type 3. Reports persist in DB (don't expire like jobs) ``` ### Empty Query ```javascript // Error: "Query must not be empty" // Recovery: 1. Always provide explicit query parameter 2. Don't rely on defaults for research ``` --- ## Performance Patterns ### Minimize Embeddings - Embeddings are CPU-intensive (~100ms each) - Use `mode: "full"` to skip semantic summary - Batch search requests when possible ### Parallel Tool Calls These tools can be called in parallel: - `ping` + `get_server_status` + `history` - Multiple `search` queries - `job_status` polling while doing other work These must be sequential: - `research` → `job_status` (wait for job_id) - `job_status` → `get_report` (wait for report_id) --- ## MCP Protocol Notes ### Task vs Job - **Task**: MCP 2025-11-25 protocol abstraction - **Job**: Internal server job system - **Mapping**: task_get/task_result wrap job_status/result ### Sampling - `sample_message` creates LLM completions via OpenRouter - Enables server-side agentic loops - Uses configured models (planning_model default) ### SSE Streaming - Async jobs provide SSE URL for real-time events - Connect to `/jobs/{job_id}/events` for streaming - Events: submitted, progress, completed, failed --- ## Testing Checklist Before using tools: - [ ] `ping {}` returns `{"pong": true}` - [ ] `get_server_status` shows `database.initialized: true` - [ ] `get_server_status` shows `embedder.ready: true` - [ ] `list_tools {}` returns expected tools for current mode After research: - [ ] Job status shows `completed` - [ ] Report ID extracted from result - [ ] `get_report` returns content - [ ] `history` shows new report

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wheattoast11/openrouter-deep-research-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server