telique-mcp 1.0.31 → 1.0.32

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,3 +1,3 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  export declare function registerKnowledge(server: McpServer): void;
3
- export declare const TELIQUE_KNOWLEDGE = "# Telique Telecom API Knowledge Base\n\nYou have access to 14 Telique tools for querying live telecom data. NEVER guess carrier names, LRNs, routing data, or CNAM \u2014 always query the API.\n\n---\n\n## CRITICAL: LERG vs LSMS \u2014 Two Different Databases\n\n**LERG** = Static telecom infrastructure reference (updated monthly from iconectiv BIRRDS)\n- NPA-NXX assignments, switches, tandems, homing arrangements, rate centers, LATAs, carrier names by OCN\n- 27 tables. NO individual phone number data.\n- Query with: `lerg_query`, `lerg_complex_query`, `lerg_tandem`, `lerg_table_info`, or `graphql_query(service=\"lerg\")`\n\n**LSMS** = Live NPAC porting data (refreshed within minutes)\n- Phone number ownership (SPID), LRN assignments, porting state\n- NO routing infrastructure (no tandems, switches, homing, rate centers, OCN names)\n- Query with: `lrn_lookup`, `lrn_relationship_query`, or `graphql_query(service=\"lsms\")`\n\n| Data Type | Database | Tool |\n|-----------|----------|------|\n| Tandem switches | **LERG** | `lerg_tandem` |\n| Switch/CLLI details | **LERG** | `lerg_query` on lerg_7 |\n| Homing arrangements | **LERG** | `lerg_query` on lerg_7_sha |\n| NPA-NXX routing (OCN, switch, LATA, rate center) | **LERG** | `lerg_query` on lerg_6 |\n| Carrier/OCN names | **LERG** | `lerg_query` on lerg_1 |\n| Current TN ownership (SPID) | **LSMS** | `lrn_lookup` |\n| Current LRN for a TN | **LSMS** | `lrn_lookup` |\n| Porting state | **LSMS** | `lrn_relationship_query` or GraphQL |\n\n---\n\n## CRITICAL: Always Dip the LRN First\n\nA ported phone number's NPA-NXX often differs from its LRN's NPA-NXX. For ANY routing question about a specific phone number:\n\n1. **`lrn_lookup`** \u2192 get the LRN and SPID\n2. Extract NPA-NXX from the **LRN** (first 3 digits = NPA, next 3 = NXX)\n3. Use the **LRN's** NPA-NXX for all LERG lookups\n\n**Example:** TN 303-629-8301\n- WRONG: Look up 303-629 in LERG \u2192 returns the original carrier's data (before porting)\n- CORRECT: `lrn_lookup(\"3036298301\")` \u2192 LRN = 7207081999 \u2192 look up 720-708 in LERG \u2192 returns current carrier\n\nThis applies to: tandem, switch, LATA, OCN, rate center \u2014 anything keyed by NPA-NXX.\n\n### The Golden Pattern for Routing Questions\n\n```\nStep 1: lrn_lookup({phone_number}) \u2192 get LRN and SPID\nStep 2: Extract NPA (first 3 digits of LRN) and NXX (next 3 digits of LRN)\nStep 3: Use LRN's NPA-NXX for LERG queries:\n - lerg_tandem({npa, nxx}) \u2192 tandem switch\n - lerg_query(\"lerg_6\", ..., \"npa={npa}&nxx={nxx}\") \u2192 OCN, switch, LATA, rate center\n - lerg_query(\"lerg_7\", ..., \"switch={clli}\") \u2192 switch details\n```\n\nOr use `lookup_tn` for a quick consolidated view (dips LRN + CNAM + DNO + LERG in parallel).\n\n---\n\n## LERG Table Reference\n\n### Big 4 \u2014 Cover ~80% of Queries\n\n**lerg_1** \u2014 OCN/carrier directory\n- Fields: ocn_num, ocn_name, abbre_ocn_name, ocn_state, category, overall_ocn\n- Use: Look up carrier name by OCN. Join from lerg_6 `ocn` \u2192 lerg_1 `ocn_num`.\n- Example: `lerg_query(\"lerg_1\", \"ocn_num,ocn_name,ocn_state\", \"ocn_num=567G\")`\n\n**lerg_6** \u2014 NPA-NXX block assignments (the workhorse)\n- Fields: npa, nxx, block_id, lata, lata_name, loc_state, ocn, aocn, switch, sha_indicator, rc_abbre, rc_type, coc_type, eff_date, status\n- Has LATA + state + NPA + NXX + OCN + switch + rate center all on one row.\n- Example: `lerg_query(\"lerg_6\", \"npa,nxx,block_id,loc_name,loc_state,ocn,switch,lata\", \"npa=720&nxx=708\")`\n\n**CRITICAL: Understanding block_id and NPA-NXX ownership:**\n- `block_id=\"A\"` = the **Code Holder** \u2014 the original LERG owner of the entire NPA-NXX. This is THE owner of the NPA-NXX.\n- `block_id=\"0\"` through `\"9\"` = **Block Holders** \u2014 carriers who received a pooled 1,000-number block (thousands-block pooling). Each block covers numbers x000-x999 within the NXX.\n- When asked \"who owns NPA-NXX 720-708?\", the answer is the OCN on the `block_id=\"A\"` row.\n- A query for `npa=720&nxx=708` may return multiple rows \u2014 one for block_id=\"A\" (the Code Holder) and additional rows for pooled blocks (0-9). Always filter or identify the \"A\" row for ownership questions.\n- To find which carrier serves a specific phone number within a pooled NXX, use the LRN dip pattern instead (the block_id approach only tells you who holds the block, not who currently serves an individual ported number).\n\n**lerg_7_sha** \u2014 Switch homing arrangements\n- Fields: switch, sha_indicator, h_trm_d_tdm (FGD tandem), host, ocn\n- Match `switch` + `sha_indicator` from lerg_6 to find the correct tandem.\n- Or use `lerg_tandem` which does the join automatically.\n\n**lerg_12** \u2014 LRN registry\n- Fields: lrn, lata, lata_name, switch, ocn, status, eff_date\n- Which company/switch established each LRN.\n\n### Supporting Tables\n\n| Table | Purpose |\n|-------|---------|\n| lerg_3 | NPA (area code) metadata \u2014 state, effective date |\n| lerg_5 | NPA/LATA cross-reference \u2014 which NPAs exist in a LATA |\n| lerg_7 | Switch/CLLI details \u2014 address, coordinates, equipment type |\n| lerg_8 | Rate center details \u2014 geography, V&H coordinates |\n| lerg_8_loc | Localities (towns) \u2192 rate centers |\n| lerg_8_pst | ZIP codes \u2192 localities (US only) |\n| lerg_9 | Homing by tandem \u2014 \"top-down\" view of which NPA-NXXs subtend a tandem |\n| lerg_4 | SS7 point codes |\n| lerg_10 | NPA-NXX \u2192 operator services ATC |\n| lerg_11 | Locality \u2192 operator services ATC |\n| lerg_16 | IP capability by LRN |\n| lerg_17 | IP capability by NPA-NXX |\n\nUse `lerg_table_info` to list all tables or get the schema for a specific one.\n\n---\n\n## LERG Query Syntax\n\nREST queries use path-based filters with `&` joining multiple conditions:\n- Single filter: `lerg_query(\"lerg_1\", \"ocn_num,ocn_name\", \"ocn_state=CO\")`\n- Multiple filters: `lerg_query(\"lerg_6\", \"npa,nxx,loc_name,ocn\", \"npa=303&nxx=629\")`\n\nFor complex queries with JOINs and advanced operators, use `lerg_complex_query`:\n```json\n{\n \"table\": \"lerg_6\",\n \"fields\": [\"npa\", \"nxx\", \"ocn\", \"loc_name\"],\n \"filters\": [{\"field\": \"npa\", \"operator\": \"eq\", \"value\": 720}],\n \"join\": {\n \"table\": \"lerg_1\",\n \"on\": [{\"left_field\": \"ocn\", \"right_field\": \"ocn_num\"}],\n \"fields\": [\"ocn_name\", \"ocn_state\"]\n }\n}\n```\n\nFilter operators: eq, ne, gt, gte, lt, lte, like, in, notin, isnull, isnotnull.\nUse `*` as the fields value to return all fields from a table.\nNote: REST `like` is **case-insensitive** (in-memory matching), unlike GraphQL LIKE which is case-sensitive (PostgreSQL).\n\n---\n\n## When to Use REST vs GraphQL\n\n| Use Case | Best Tool | Why |\n|----------|-----------|-----|\n| Single LRN/SPID for a phone number | `lrn_lookup` (REST) | Sub-millisecond, in-memory |\n| Carrier name by OCN | `lerg_query` (REST) | Simple single-field lookup |\n| NPA-NXX routing info | `lerg_query` (REST) | Fast, straightforward |\n| Tandem routing | `lerg_tandem` (REST) | Pre-built JOIN, optimized |\n| NPA-NXX + carrier name + switch in one call | `graphql_query` (LERG) | Nested relationships avoid multiple round trips |\n| Filter by fields not in REST (e.g., all switches for an OCN) | `graphql_query` (LERG) | FilterInput supports any field |\n| Cross-table JOIN with arbitrary conditions | `graphql_query` (LERG dynamicJoin) | Only way to do ad-hoc joins |\n| All phone numbers for an LRN (paginated with totalCount) | `graphql_query` (LSMS) | SVConnection returns totalCount + hasMore |\n| Quick profile of a phone number | `lookup_tn` (composite) | Parallel dip across LRN + CNAM + DNO + LERG |\n\n**Rule of thumb:** Use REST for simple lookups (one table, one or two filters). Use GraphQL when you need joins, relationship traversal, or fields not exposed by REST endpoints.\n\n---\n\n## LSMS / LRN REST Endpoints\n\nThe LRN API serves live NPAC porting data from an in-memory Judy Array store (500M+ records, sub-millisecond) backed by a PostgreSQL LSMS database.\n\n### LRN Lookup (`lrn_lookup` tool)\n\n`GET /v1/telique/lrn/{phone_number}?format=json`\n\nReturns the current LRN and carrier for a phone number. This is the fastest lookup \u2014 served from in-memory store, not PostgreSQL.\n\n**JSON response shape:**\n```json\n{\n \"phone_number\": \"3036298301\",\n \"lrn\": \"7207081999\",\n \"status\": \"success\",\n \"timestamp\": \"2025-08-07T02:30:00Z\",\n \"metadata\": {\n \"spid\": \"567G\",\n \"lnp_type\": \"lspp\"\n }\n}\n```\n\nDefault format is plain text (`LRN;SPID`, e.g., `7207081999;567G`). Use `?format=json` for structured response.\n\n**Note:** The REST LRN response does not include port-activation history. For the authoritative NPAC port activation timestamp, query LSMS GraphQL: `subscriptionVersion(phoneNumber) { activationTimestamp }`.\n\n### LSMS Relationship Queries (`lrn_relationship_query` tool)\n\nQuery relationships between phone numbers, LRNs, and SPIDs from the LSMS PostgreSQL database. These hit the database directly and have higher latency than the in-memory LRN lookup.\n\n**6 query types and their endpoints:**\n\n| query_type | Endpoint | Description |\n|------------|----------|-------------|\n| `phones_by_lrn` | `GET /v1/telique/lsms/list/phone_number?lrn={value}` | All phone numbers for a given LRN |\n| `phones_by_spid` | `GET /v1/telique/lsms/list/phone_number?spid={value}` | All phone numbers for a given SPID |\n| `spid_by_lrn` | `GET /v1/telique/lsms/list/spid?lrn={value}` | All SPIDs associated with a given LRN |\n| `spid_by_phone` | `GET /v1/telique/lsms/list/spid?phone_number={value}` | All SPIDs for a given phone number |\n| `lrn_by_spid` | `GET /v1/telique/lsms/list/lrn?spid={value}` | All LRNs for a given SPID |\n| `lrn_by_phone` | `GET /v1/telique/lsms/list/lrn?phone_number={value}` | All LRNs for a given phone number |\n\n**Constraints:**\n- Exactly ONE query parameter per request (multiple parameters return a validation error)\n- Results are filtered to active records only\n- Phone numbers and LRNs are returned as strings\n\n**Example response (phones_by_lrn):**\n```json\n{\n \"phone_numbers\": [\"3036298301\", \"3039982743\", \"3033334444\"],\n \"count\": 3,\n \"query\": { \"lrn\": \"7207081999\", \"spid\": null, \"phone_number\": null }\n}\n```\n\n---\n\n## CNAM (Caller Name)\n\n`cnam_lookup` queries TransUnion's LIDB for the caller name associated with a phone number.\n\n- Returns: calling_name (up to 15 chars), calling_name_status (available/unavailable), presentation_indicator (allowed/restricted)\n- Results cached server-side for 24 hours\n- \"WIRELESS CALLER\" typically means the carrier hasn't provisioned a specific CNAM entry\n\n---\n\n## DNO (Do Not Originate)\n\n`dno_check` checks if a phone number should never appear as a caller ID.\n\n- DNO numbers belong to entities that only receive calls (IRS, major banks, government agencies)\n- If is_dno=true, the number appearing as caller ID indicates **spoofing/fraud**\n- Supports prefix matching: 3-digit (NPA), 6-digit (NPA-NXX), 7-digit, or 10-digit patterns\n- Response includes: is_dno, matched_pattern, source\n- Phone numbers are auto-normalized: E.164 (+12003456789), domestic (12003456789), and international (0012003456789) formats all accepted\n\n---\n\n## RouteLink \u2014 Toll-Free Number Routing\n\n**What is a toll-free number?** A phone number with an 8XX NPA (area code) that is free for the caller \u2014 the called party pays. Toll-free NPAs: **800, 888, 877, 866, 855, 844, 833, 822**. Any 10-digit number starting with one of these NPAs is a toll-free number (also called TFN or CRN in RouteLink context).\n\nToll-free numbers are managed by the **Somos TFN Registry**, not NPAC/LSMS. They have their own routing system (CPR decision trees) and their own management hierarchy (RespOrgs, not SPIDs). Use the RouteLink tools for toll-free lookups \u2014 do NOT use `lrn_lookup` for toll-free numbers (they don't have LRNs).\n\n### ROR (Responsible Organization)\n`routelink_lookup` with lookup_type=\"ror\" returns the RespOrg managing a toll-free number.\n- RespOrg is a 5-char code (e.g., \"NEX01\", \"TZN99\")\n- Only needs the CRN (toll-free number), no ANI/LATA required\n\n### CIC (Carrier Identification Code)\n`routelink_lookup` with lookup_type=\"cic\" or \"cicror\" returns which carrier handles calls to a toll-free number FROM a specific caller (ANI) in a specific LATA.\n- Requires: crn, ani (10-digit), lata (3-digit)\n- Common carrier codes: 0288 (AT&T), 0222 (MCI/Verizon), 0333 (Sprint), 0432 (Lumen)\n\n### CPR (Call Processing Record)\n`routelink_cpr` retrieves the full routing decision tree for a toll-free number.\n\n**Decision tree node types:**\n| Node | Description |\n|------|-------------|\n| [LATA] | Routes by caller's LATA |\n| [NPA] | Routes by caller's area code |\n| [NXX] | Routes by caller's exchange |\n| [STATE] | Routes by caller's state |\n| [DAY_OF_WEEK] | Routes by day (1-7, Sunday=1) |\n| [TIME_OF_DAY] | Routes by time (15-min intervals) |\n| [PERCENT] | Percentage-based load balancing |\n| [ANI] | Routes by specific caller number |\n\n**Action types:** Carrier XXXX (4-digit carrier code), Template XXXXXXXXXX (reference to template CRN), Routing XXXXX, NMC X (Network Management Class)\n\n**Common patterns:**\n- Simple: All calls \u2192 one carrier \u2192 one termination number\n- Time-of-day: Business hours \u2192 office, after hours \u2192 answering service\n- Geographic: Different terminations per LATA/state/NPA\n- Percentage: Load balancing across call centers (e.g., 60%/40%)\n\nUse `expand=true` (default) to recursively resolve template references into their full decision trees.\n\n---\n\n## GraphQL\n\nUse `graphql_query` for complex queries not possible with REST:\n- Cross-table relationship joins (lerg6 \u2192 carrier, lerg6 \u2192 switchInfo, lerg7Sha \u2192 tandemSwitch)\n- Filtering by fields not in REST endpoints\n- Multiple related data points in one query\n\n### LERG GraphQL (`service=\"lerg\"`)\n\n**CRITICAL naming rules:**\n- **Query names** are camelCase: `lerg1`, `lerg6`, `lerg7Sha`, `lerg7ShaIns`, `lerg12`, etc.\n- **Object-type names use a `Gql` prefix.** `__type(name: \"Lerg6\")` returns null \u2014 the actual type is `GqlLerg6`. Rule: snake_case table ID \u2192 PascalCase + `Gql` prefix (`lerg_6` \u2192 `GqlLerg6`, `lerg_7_sha` \u2192 `GqlLerg7Sha`, `lerg_8_loc` \u2192 `GqlLerg8Loc`). Use this when introspecting types directly.\n- **Return fields** MUST be camelCase: `ocnName`, `locState`, `locName`, `shaIndicator`, `hTrmDTdm`\n- **REST fields are snake_case; GraphQL fields are camelCase \u2014 1:1 convertible.** `coc_type` \u2194 `cocType`, `loc_name` \u2194 `locName`, `ocn_num` \u2194 `ocnNum`, `sha_indicator` \u2194 `shaIndicator`. GraphQL `FilterInput` `field:` accepts both forms; REST query paths and GraphQL selection sets do not.\n- **Filter field names** accept BOTH camelCase (`ocnName`) and snake_case (`ocn_name`)\n- **All values are strings** \u2014 even numeric fields. Always quote: `value: \"720\"` not `value: 720`\n- **GraphQL LIKE is case-sensitive (SQL)** \u2014 LERG data is stored UPPERCASE, so patterns must be uppercase: `%VERIZON%` not `%verizon%`. (The REST `like` operator is case-insensitive \u2014 this only applies to GraphQL.)\n\n**FilterInput:**\n```graphql\n{ field: \"ocnName\", op: LIKE, value: \"%VERIZON%\" } # partial match (UPPERCASE!)\n{ field: \"npa\", op: EQ, value: \"720\" } # exact match\n{ field: \"npa\", op: IN, values: [\"212\", \"646\", \"917\"] } # IN uses 'values' (plural), not 'value'\n```\n\nOperators: EQ, NE, GT, GTE, LT, LTE, LIKE, IN, IS_NULL, IS_NOT_NULL\n\n**Predefined relationships** (avoid N+1 \u2014 use these instead of separate queries):\n- `lerg6` \u2192 `carrier` (joins to lerg1 via OCN), `switchInfo` (\u2192 lerg7), `homingArrangements` (\u2192 lerg7Sha)\n- `lerg7` \u2192 `carrier` (\u2192 lerg1)\n- `lerg7Sha` \u2192 `tandemSwitch` (\u2192 lerg7)\n\n**Example \u2014 find all Verizon OCNs:**\n```graphql\n{\n lerg1(\n filters: [{ field: \"ocnName\", op: LIKE, value: \"%VERIZON%\" }]\n pagination: { limit: 10 }\n ) {\n ocnNum\n ocnName\n ocnState\n category\n }\n}\n```\n\n**Example \u2014 NPA-NXX with carrier and switch in one query:**\n```graphql\n{\n lerg6(\n filters: [{ field: \"npa\", op: EQ, value: \"303\" }, { field: \"nxx\", op: EQ, value: \"629\" }]\n pagination: { limit: 1 }\n ) {\n npa nxx ocn locName switch\n carrier { ocnNum ocnName ocnState }\n switchInfo { switch eqpType swCity swState }\n homingArrangements {\n shaIndicator hTrmDTdm\n tandemSwitch { switch swCity swState }\n }\n }\n}\n```\n\n**dynamicJoin** \u2014 for arbitrary cross-table SQL joins (returns raw JSON):\n```graphql\n{\n dynamicJoin(input: {\n table: \"lerg_6\"\n fields: [\"npa\", \"nxx\", \"ocn\", \"locName\"]\n filters: [{ field: \"locName\", op: LIKE, value: \"%DENVER%\" }]\n join: {\n table: \"lerg_1\"\n fields: [\"ocnName\", \"category\"]\n on: [{ leftField: \"ocn\", rightField: \"ocnNum\" }]\n joinType: \"INNER\"\n }\n pagination: { limit: 10 }\n })\n}\n```\nNote: dynamicJoin uses snake_case table IDs (lerg_6, lerg_1, lerg_7_sha) and returns raw PostgreSQL column names (UPPERCASE with spaces, e.g., `\"OCN_NAME\"`, `\"LOC NAME\"`, `\"EFF DATE\"`), NOT GraphQL camelCase.\n\n### LSMS GraphQL (`service=\"lsms\"`)\n\nThe LSMS GraphQL API is a **completely separate implementation** from LERG GraphQL. It has different query patterns, different field naming, and different schema design. Do NOT use LERG-style FilterInput syntax with LSMS.\n\n**5 tables:**\n\n| Table | ~Rows | Requires Filter? |\n|-------|-------|------------------|\n| subscriptionVersions | 514M | Yes (phoneNumber, lrn, or spid) |\n| numberBlocks | 751K | Yes (npanxxx, spid, or lrn) |\n| serviceProviders | 5.2K | No |\n| locationRoutingNumbers | 56K | No |\n| npanxx | 192K | No |\n\n**Query patterns (NOT FilterInput \u2014 uses typed named parameters):**\n```graphql\n# Single phone number lookup\n{ subscriptionVersion(phoneNumber: \"3036298301\") { phoneNumber lrn spid serviceProvider { name } } }\n\n# Paginated list by LRN (returns totalCount, hasMore)\n{ subscriptionVersionsByLrn(lrn: \"7207081999\", limit: 10) { totalCount hasMore items { phoneNumber spid } } }\n\n# Paginated list by SPID\n{ subscriptionVersionsBySpid(spid: \"567G\", limit: 10) { totalCount hasMore items { phoneNumber lrn } } }\n\n# Number block lookup (single)\n{ numberBlock(npanxxx: \"3035551\") { npanxxx lrn spid serviceProvider { name } } }\n\n# Number blocks by SPID or LRN (paginated \u2014 at least one filter required)\n{ numberBlocks(spid: \"567G\", limit: 10) { totalCount hasMore items { npanxxx lrn spid } } }\n\n# Single carrier lookup (note: composite PK \u2014 same SPID may exist in multiple regions)\n{ serviceProvider(spid: \"567G\") { spid name npacRegion status contactInfo } }\n\n# List carriers (paginated)\n{ serviceProviders(limit: 20) { spid name npacRegion } }\n\n# LRN metadata\n{ locationRoutingNumber(lrn: \"7207081999\") { lrn ocn regionId status switchInfo } }\n\n# NPA-NXX single lookup\n{ npanxx(npa: \"303\", nxx: \"629\") { npa nxx spid effectiveTimestamp serviceProvider { name } } }\n\n# NPA-NXX codes for a carrier (paginated)\n{ npanxxBySpid(spid: \"567G\", limit: 50) { npa nxx effectiveTimestamp } }\n\n# Database statistics\n{ lsmsStats { activeSubscriptionVersions activeNumberBlocks totalServiceProviders totalLocationRoutingNumbers activeNpanxx } }\n```\n\n**Relationships** (use DataLoader batching \u2014 no N+1):\n- subscriptionVersion \u2192 `serviceProvider`, `lrnMetadata`\n- numberBlock \u2192 `serviceProvider`, `lrnMetadata`\n- npanxx \u2192 `serviceProvider`\n\n**Safety limits:** max 1000 results, depth 5, complexity 200, 10-second statement timeout\n**Auto-filters:** Soft-deletable records filter to is_active = true automatically\n**Note:** Phone numbers/LRNs are strings (stored as BIGINT but GraphQL Int is 32-bit). SPIDs are auto-trimmed (stored as CHAR(4) with trailing spaces).\n**Note:** Service providers have a composite PK of (spid, npac_region) \u2014 the same SPID may appear in multiple NPAC regions.\n\n---\n\n## REST Paths for Direct API Access\n\nThe MCP tools wrap these HTTP endpoints. Use this table when calling the Telique API directly with `curl` or another HTTP client. Base URL: `https://api.telique.ringer.tel`. Authentication: `-H \"x-api-token: tlq_\u2026\"` (per-request header, never in query string).\n\n| Tool | Method | Path | Notes |\n|------|--------|------|-------|\n| `lrn_lookup` | GET | `/v1/telique/lrn/{phone_number}` | Add `?format=json` for structured response; default is `LRN;SPID` plain text |\n| `cnam_lookup` | GET | `/v1/telique/cnam/{phone_number}` | Returns calling_name, presentation_indicator |\n| `dno_check` | GET | `/v1/telique/dno/{phone_number}` | Add `?format=json` for details; default is `true`/`false` text |\n| `lrn_relationship_query` | GET | `/v1/telique/lsms/list/{resource}?{filter}={value}` | `resource` \u2208 {phone_number, spid, lrn}; filter \u2208 {lrn, spid, phone_number}; exactly one filter |\n| `lerg_table_info` | GET | `/v1/telique/lerg/tables` or `/v1/telique/lerg/tables/{table_name}` | No args = list all tables |\n| `lerg_query` | GET | `/v1/telique/lerg/{table_name}/{fields}/{query}` | Example: `/lerg/lerg_6/npa,nxx,ocn/npa=303&nxx=629` |\n| `lerg_complex_query` | POST | `/v1/telique/lerg/query` | JSON body with table, fields, filters, join, limit, offset |\n| `lerg_tandem` | GET | `/v1/telique/lerg/tandem?npa={npa}&nxx={nxx}` | Pre-joined tandem lookup |\n| `routelink_lookup` (ror) | GET | `/v1/telique/ror/{crn}` | Responsible Organization for a toll-free number |\n| `routelink_lookup` (cic/cicror) | GET | `/v1/telique/{cic\\|cicror}/{crn}/{ani}/{lata}` | CIC or CIC+ROR for a toll-free call |\n| `routelink_ror_query` | GET | `/v1/telique/ror/{ror}/{tfns\\|cprs}` | List TFNs or CPRs for a ROR; paginated `?limit=&offset=` |\n| `routelink_cpr` | GET | `/v1/telique/cpr/{crn}` | Call Processing Record; add `?expand=true` to inline templates |\n| `graphql_query` (lerg) | POST | `/v1/telique/lerg/gql` | JSON body `{\"query\":\"...\"}`; GET returns GraphiQL playground HTML |\n| `graphql_query` (lsms) | POST | `/v1/telique/lsms/gql` | JSON body `{\"query\":\"...\"}`; GET returns GraphiQL playground HTML |\n| `lookup_tn` | \u2014 | (composite) | Not a single endpoint \u2014 fans out to `/lrn/`, `/cnam/`, `/dno/`, `/lerg/\u2026` in parallel |\n\n**Note on RouteLink paths**: there is NO `/routelink/` segment. The public OpenAPI spec at `https://telique.ringer.tel/docs/api-reference` historically listed `/v1/telique/routelink/cpr/{crn}` etc. \u2014 those paths return 404. The real paths are bare (`/v1/telique/cpr/{crn}`) as shown above.\n\n---\n\n## Key Telecom Concepts\n\n| Term | Definition |\n|------|-----------|\n| **LRN** | Location Routing Number \u2014 identifies the switch serving a ported number |\n| **SPID** | Service Provider ID \u2014 identifies the carrier that owns a number |\n| **OCN** | Operating Company Number \u2014 4-char carrier identifier (often same as SPID) |\n| **NPA** | Numbering Plan Area \u2014 3-digit area code |\n| **NXX** | Exchange code \u2014 next 3 digits after area code |\n| **LATA** | Local Access Transport Area \u2014 geographic region for call routing |\n| **CLLI** | Common Language Location Identifier \u2014 8-11 char switch/building code |\n| **CRN** | Call Routing Number \u2014 a toll-free number in RouteLink context |\n| **ROR/RespOrg** | Responsible Organization \u2014 entity managing a toll-free number's routing |\n| **CIC** | Carrier Identification Code \u2014 identifies which carrier handles a toll-free call |\n| **CPR** | Call Processing Record \u2014 routing decision tree for a toll-free number |\n| **Rate Center** | Geographic area defining local calling boundaries |\n| **Tandem** | A switching office that connects local switches to the long-distance network |\n| **Homing** | The relationship between a local switch and its tandem |\n\n---\n\n## Common Mistakes to Avoid\n\n1. **Never guess carrier names** \u2014 always query lerg_1 by OCN\n2. **Never skip the LRN dip** \u2014 ported TNs have different NPA-NXX than their LRN\n3. **Never look for tandem/switch data in LSMS** \u2014 LSMS has no infrastructure data\n4. **Never look for TN-level data in LERG** \u2014 LERG has no per-phone-number data\n5. **Never query LSMS subscriptionVersions without a filter** \u2014 514M rows will timeout\n6. **Always use the LRN's NPA-NXX** (not the TN's) for LERG routing lookups\n7. **GraphQL return fields must be camelCase** \u2014 `ocnName` not `ocn_name`, `locState` not `loc_state`\n8. **GraphQL LIKE patterns must be UPPERCASE** \u2014 LERG data is uppercase in PostgreSQL, so `%VERIZON%` works but `%verizon%` returns nothing. (REST `like` is case-insensitive \u2014 this only applies to GraphQL.)\n9. **IN operator uses `values` (plural)** \u2014 `{ field: \"npa\", op: IN, values: [\"212\", \"646\"] }` not `value`\n";
3
+ export declare const TELIQUE_KNOWLEDGE = "# Telique Telecom API Knowledge Base\n\nYou have access to 14 Telique tools for querying live telecom data. NEVER guess carrier names, LRNs, routing data, or CNAM \u2014 always query the API.\n\n---\n\n## CRITICAL: LERG vs LSMS \u2014 Two Different Databases\n\n**LERG** = Static telecom infrastructure reference (updated monthly from iconectiv BIRRDS)\n- NPA-NXX assignments, switches, tandems, homing arrangements, rate centers, LATAs, carrier names by OCN\n- 27 tables. NO individual phone number data.\n- Query with: `lerg_query`, `lerg_complex_query`, `lerg_tandem`, `lerg_table_info`, or `graphql_query(service=\"lerg\")`\n\n**LSMS** = Live NPAC porting data (refreshed within minutes)\n- Phone number ownership (SPID), LRN assignments, porting state\n- NO routing infrastructure (no tandems, switches, homing, rate centers, OCN names)\n- Query with: `lrn_lookup`, `lrn_relationship_query`, or `graphql_query(service=\"lsms\")`\n\n| Data Type | Database | Tool |\n|-----------|----------|------|\n| Tandem switches | **LERG** | `lerg_tandem` |\n| Switch/CLLI details | **LERG** | `lerg_query` on lerg_7 |\n| Homing arrangements | **LERG** | `lerg_query` on lerg_7_sha |\n| NPA-NXX routing (OCN, switch, LATA, rate center) | **LERG** | `lerg_query` on lerg_6 |\n| Carrier/OCN names | **LERG** | `lerg_query` on lerg_1 |\n| Current TN ownership (SPID) | **LSMS** | `lrn_lookup` |\n| Current LRN for a TN | **LSMS** | `lrn_lookup` |\n| Porting state | **LSMS** | `lrn_relationship_query` or GraphQL |\n\n---\n\n## CRITICAL: Always Dip the LRN First\n\nA ported phone number's NPA-NXX often differs from its LRN's NPA-NXX. For ANY routing question about a specific phone number:\n\n1. **`lrn_lookup`** \u2192 get the LRN and SPID\n2. Extract NPA-NXX from the **LRN** (first 3 digits = NPA, next 3 = NXX)\n3. Use the **LRN's** NPA-NXX for all LERG lookups\n\n**Example:** TN 303-629-8301\n- WRONG: Look up 303-629 in LERG \u2192 returns the original carrier's data (before porting)\n- CORRECT: `lrn_lookup(\"3036298301\")` \u2192 LRN = 7207081999 \u2192 look up 720-708 in LERG \u2192 returns current carrier\n\nThis applies to: tandem, switch, LATA, OCN, rate center \u2014 anything keyed by NPA-NXX.\n\n### The Golden Pattern for Routing Questions\n\n```\nStep 1: lrn_lookup({phone_number}) \u2192 get LRN and SPID\nStep 2: Extract NPA (first 3 digits of LRN) and NXX (next 3 digits of LRN)\nStep 3: Use LRN's NPA-NXX for LERG queries:\n - lerg_tandem({npa, nxx}) \u2192 tandem switch\n - lerg_query(\"lerg_6\", ..., \"npa={npa}&nxx={nxx}\") \u2192 OCN, switch, LATA, rate center\n - lerg_query(\"lerg_7\", ..., \"switch={clli}\") \u2192 switch details\n```\n\nOr use `lookup_tn` for a quick consolidated view (dips LRN + CNAM + DNO + LERG in parallel).\n\n---\n\n## LERG Table Reference\n\n### Big 4 \u2014 Cover ~80% of Queries\n\n**lerg_1** \u2014 OCN/carrier directory\n- Fields: ocn_num, ocn_name, abbre_ocn_name, ocn_state, category, overall_ocn\n- Use: Look up carrier name by OCN. Join from lerg_6 `ocn` \u2192 lerg_1 `ocn_num`.\n- Example: `lerg_query(\"lerg_1\", \"ocn_num,ocn_name,ocn_state\", \"ocn_num=567G\")`\n\n**lerg_6** \u2014 NPA-NXX block assignments (the workhorse)\n- Fields: npa, nxx, block_id, lata, lata_name, loc_state, ocn, aocn, switch, sha_indicator, rc_abbre, rc_type, coc_type, eff_date, status\n- Has LATA + state + NPA + NXX + OCN + switch + rate center all on one row.\n- Example: `lerg_query(\"lerg_6\", \"npa,nxx,block_id,loc_name,loc_state,ocn,switch,lata\", \"npa=720&nxx=708\")`\n\n**CRITICAL: Understanding block_id and NPA-NXX ownership:**\n- `block_id=\"A\"` = the **Code Holder** \u2014 the original LERG owner of the entire NPA-NXX. This is THE owner of the NPA-NXX.\n- `block_id=\"0\"` through `\"9\"` = **Block Holders** \u2014 carriers who received a pooled 1,000-number block (thousands-block pooling). Each block covers numbers x000-x999 within the NXX.\n- When asked \"who owns NPA-NXX 720-708?\", the answer is the OCN on the `block_id=\"A\"` row.\n- A query for `npa=720&nxx=708` may return multiple rows \u2014 one for block_id=\"A\" (the Code Holder) and additional rows for pooled blocks (0-9). Always filter or identify the \"A\" row for ownership questions.\n- To find which carrier serves a specific phone number within a pooled NXX, use the LRN dip pattern instead (the block_id approach only tells you who holds the block, not who currently serves an individual ported number).\n\n**lerg_7_sha** \u2014 Switch homing arrangements\n- Fields: switch, sha_indicator, h_trm_d_tdm (FGD tandem), host, ocn\n- Match `switch` + `sha_indicator` from lerg_6 to find the correct tandem.\n- Or use `lerg_tandem` which does the join automatically.\n\n**lerg_12** \u2014 LRN registry\n- Fields: lrn, lata, lata_name, switch, ocn, status, eff_date\n- Which company/switch established each LRN.\n\n### Supporting Tables\n\n| Table | Purpose |\n|-------|---------|\n| lerg_3 | NPA (area code) metadata \u2014 state, effective date |\n| lerg_5 | NPA/LATA cross-reference \u2014 which NPAs exist in a LATA |\n| lerg_7 | Switch/CLLI details \u2014 address, coordinates, equipment type |\n| lerg_8 | Rate center details \u2014 geography, V&H coordinates |\n| lerg_8_loc | Localities (towns) \u2192 rate centers |\n| lerg_8_pst | ZIP codes \u2192 localities (US only) |\n| lerg_9 | Homing by tandem \u2014 \"top-down\" view of which NPA-NXXs subtend a tandem |\n| lerg_4 | SS7 point codes |\n| lerg_10 | NPA-NXX \u2192 operator services ATC |\n| lerg_11 | Locality \u2192 operator services ATC |\n| lerg_16 | IP capability by LRN |\n| lerg_17 | IP capability by NPA-NXX |\n\nUse `lerg_table_info` to list all tables or get the schema for a specific one.\n\n---\n\n## LERG Query Syntax\n\nREST queries use path-based filters with `&` joining multiple conditions:\n- Single filter: `lerg_query(\"lerg_1\", \"ocn_num,ocn_name\", \"ocn_state=CO\")`\n- Multiple filters: `lerg_query(\"lerg_6\", \"npa,nxx,loc_name,ocn\", \"npa=303&nxx=629\")`\n\nFor complex queries with JOINs and advanced operators, use `lerg_complex_query`:\n```json\n{\n \"table\": \"lerg_6\",\n \"fields\": [\"npa\", \"nxx\", \"ocn\", \"loc_name\"],\n \"filters\": [{\"field\": \"npa\", \"operator\": \"eq\", \"value\": 720}],\n \"join\": {\n \"table\": \"lerg_1\",\n \"on\": [{\"left_field\": \"ocn\", \"right_field\": \"ocn_num\"}],\n \"fields\": [\"ocn_name\", \"ocn_state\"]\n }\n}\n```\n\nFilter operators: eq, ne, gt, gte, lt, lte, like, in, notin, isnull, isnotnull.\nUse `*` as the fields value to return all fields from a table.\nNote: REST `like` is **case-insensitive** (in-memory matching), unlike GraphQL LIKE which is case-sensitive (PostgreSQL).\n\n---\n\n## When to Use REST vs GraphQL\n\n| Use Case | Best Tool | Why |\n|----------|-----------|-----|\n| Single LRN/SPID for a phone number | `lrn_lookup` (REST) | Sub-millisecond, in-memory |\n| Carrier name by OCN | `lerg_query` (REST) | Simple single-field lookup |\n| NPA-NXX routing info | `lerg_query` (REST) | Fast, straightforward |\n| Tandem routing | `lerg_tandem` (REST) | Pre-built JOIN, optimized |\n| NPA-NXX + carrier name + switch in one call | `graphql_query` (LERG) | Nested relationships avoid multiple round trips |\n| Filter by fields not in REST (e.g., all switches for an OCN) | `graphql_query` (LERG) | FilterInput supports any field |\n| Cross-table JOIN with arbitrary conditions | `graphql_query` (LERG dynamicJoin) | Only way to do ad-hoc joins |\n| All phone numbers for an LRN (paginated with totalCount) | `graphql_query` (LSMS) | SVConnection returns totalCount + hasMore |\n| Quick profile of a phone number | `lookup_tn` (composite) | Parallel dip across LRN + CNAM + DNO + LERG |\n\n**Rule of thumb:** Use REST for simple lookups (one table, one or two filters). Use GraphQL when you need joins, relationship traversal, or fields not exposed by REST endpoints.\n\n---\n\n## LSMS / LRN REST Endpoints\n\nThe LRN API serves live NPAC porting data from an in-memory Judy Array store (500M+ records, sub-millisecond) backed by a PostgreSQL LSMS database.\n\n### LRN Lookup (`lrn_lookup` tool)\n\n`GET /v1/lrn/{phone_number}?format=json`\n\nReturns the current LRN and carrier for a phone number. This is the fastest lookup \u2014 served from in-memory store, not PostgreSQL.\n\n**JSON response shape:**\n```json\n{\n \"phone_number\": \"3036298301\",\n \"lrn\": \"7207081999\",\n \"status\": \"success\",\n \"timestamp\": \"2025-08-07T02:30:00Z\",\n \"metadata\": {\n \"spid\": \"567G\",\n \"lnp_type\": \"lspp\"\n }\n}\n```\n\nDefault format is plain text (`LRN;SPID`, e.g., `7207081999;567G`). Use `?format=json` for structured response.\n\n**Note:** The REST LRN response does not include port-activation history. For the authoritative NPAC port activation timestamp, query LSMS GraphQL: `subscriptionVersion(phoneNumber) { activationTimestamp }`.\n\n### LSMS Relationship Queries (`lrn_relationship_query` tool)\n\nQuery relationships between phone numbers, LRNs, and SPIDs from the LSMS PostgreSQL database. These hit the database directly and have higher latency than the in-memory LRN lookup.\n\n**6 query types and their endpoints:**\n\n| query_type | Endpoint | Description |\n|------------|----------|-------------|\n| `phones_by_lrn` | `GET /v1/lsms/list/phone_number?lrn={value}` | All phone numbers for a given LRN |\n| `phones_by_spid` | `GET /v1/lsms/list/phone_number?spid={value}` | All phone numbers for a given SPID |\n| `spid_by_lrn` | `GET /v1/lsms/list/spid?lrn={value}` | All SPIDs associated with a given LRN |\n| `spid_by_phone` | `GET /v1/lsms/list/spid?phone_number={value}` | All SPIDs for a given phone number |\n| `lrn_by_spid` | `GET /v1/lsms/list/lrn?spid={value}` | All LRNs for a given SPID |\n| `lrn_by_phone` | `GET /v1/lsms/list/lrn?phone_number={value}` | All LRNs for a given phone number |\n\n**Constraints:**\n- Exactly ONE query parameter per request (multiple parameters return a validation error)\n- Results are filtered to active records only\n- Phone numbers and LRNs are returned as strings\n\n**Example response (phones_by_lrn):**\n```json\n{\n \"phone_numbers\": [\"3036298301\", \"3039982743\", \"3033334444\"],\n \"count\": 3,\n \"query\": { \"lrn\": \"7207081999\", \"spid\": null, \"phone_number\": null }\n}\n```\n\n---\n\n## CNAM (Caller Name)\n\n`cnam_lookup` queries TransUnion's LIDB for the caller name associated with a phone number.\n\n- Returns: calling_name (up to 15 chars), calling_name_status (available/unavailable), presentation_indicator (allowed/restricted)\n- Results cached server-side for 24 hours\n- \"WIRELESS CALLER\" typically means the carrier hasn't provisioned a specific CNAM entry\n\n---\n\n## DNO (Do Not Originate)\n\n`dno_check` checks if a phone number should never appear as a caller ID.\n\n- DNO numbers belong to entities that only receive calls (IRS, major banks, government agencies)\n- If is_dno=true, the number appearing as caller ID indicates **spoofing/fraud**\n- Supports prefix matching: 3-digit (NPA), 6-digit (NPA-NXX), 7-digit, or 10-digit patterns\n- Response includes: is_dno, matched_pattern, source\n- Phone numbers are auto-normalized: E.164 (+12003456789), domestic (12003456789), and international (0012003456789) formats all accepted\n\n---\n\n## RouteLink \u2014 Toll-Free Number Routing\n\n**What is a toll-free number?** A phone number with an 8XX NPA (area code) that is free for the caller \u2014 the called party pays. Toll-free NPAs: **800, 888, 877, 866, 855, 844, 833, 822**. Any 10-digit number starting with one of these NPAs is a toll-free number (also called TFN or CRN in RouteLink context).\n\nToll-free numbers are managed by the **Somos TFN Registry**, not NPAC/LSMS. They have their own routing system (CPR decision trees) and their own management hierarchy (RespOrgs, not SPIDs). Use the RouteLink tools for toll-free lookups \u2014 do NOT use `lrn_lookup` for toll-free numbers (they don't have LRNs).\n\n### ROR (Responsible Organization)\n`routelink_lookup` with lookup_type=\"ror\" returns the RespOrg managing a toll-free number.\n- RespOrg is a 5-char code (e.g., \"NEX01\", \"TZN99\")\n- Only needs the CRN (toll-free number), no ANI/LATA required\n\n### CIC (Carrier Identification Code)\n`routelink_lookup` with lookup_type=\"cic\" or \"cicror\" returns which carrier handles calls to a toll-free number FROM a specific caller (ANI) in a specific LATA.\n- Requires: crn, ani (10-digit), lata (3-digit)\n- Common carrier codes: 0288 (AT&T), 0222 (MCI/Verizon), 0333 (Sprint), 0432 (Lumen)\n\n### CPR (Call Processing Record)\n`routelink_cpr` retrieves the full routing decision tree for a toll-free number.\n\n**Decision tree node types:**\n| Node | Description |\n|------|-------------|\n| [LATA] | Routes by caller's LATA |\n| [NPA] | Routes by caller's area code |\n| [NXX] | Routes by caller's exchange |\n| [STATE] | Routes by caller's state |\n| [DAY_OF_WEEK] | Routes by day (1-7, Sunday=1) |\n| [TIME_OF_DAY] | Routes by time (15-min intervals) |\n| [PERCENT] | Percentage-based load balancing |\n| [ANI] | Routes by specific caller number |\n\n**Action types:** Carrier XXXX (4-digit carrier code), Template XXXXXXXXXX (reference to template CRN), Routing XXXXX, NMC X (Network Management Class)\n\n**Common patterns:**\n- Simple: All calls \u2192 one carrier \u2192 one termination number\n- Time-of-day: Business hours \u2192 office, after hours \u2192 answering service\n- Geographic: Different terminations per LATA/state/NPA\n- Percentage: Load balancing across call centers (e.g., 60%/40%)\n\nUse `expand=true` (default) to recursively resolve template references into their full decision trees.\n\n---\n\n## GraphQL\n\nUse `graphql_query` for complex queries not possible with REST:\n- Cross-table relationship joins (lerg6 \u2192 carrier, lerg6 \u2192 switchInfo, lerg7Sha \u2192 tandemSwitch)\n- Filtering by fields not in REST endpoints\n- Multiple related data points in one query\n\n### LERG GraphQL (`service=\"lerg\"`)\n\n**CRITICAL naming rules:**\n- **Query names** are camelCase: `lerg1`, `lerg6`, `lerg7Sha`, `lerg7ShaIns`, `lerg12`, etc.\n- **Object-type names use a `Gql` prefix.** `__type(name: \"Lerg6\")` returns null \u2014 the actual type is `GqlLerg6`. Rule: snake_case table ID \u2192 PascalCase + `Gql` prefix (`lerg_6` \u2192 `GqlLerg6`, `lerg_7_sha` \u2192 `GqlLerg7Sha`, `lerg_8_loc` \u2192 `GqlLerg8Loc`). Use this when introspecting types directly.\n- **Return fields** MUST be camelCase: `ocnName`, `locState`, `locName`, `shaIndicator`, `hTrmDTdm`\n- **REST fields are snake_case; GraphQL fields are camelCase \u2014 1:1 convertible.** `coc_type` \u2194 `cocType`, `loc_name` \u2194 `locName`, `ocn_num` \u2194 `ocnNum`, `sha_indicator` \u2194 `shaIndicator`. GraphQL `FilterInput` `field:` accepts both forms; REST query paths and GraphQL selection sets do not.\n- **Filter field names** accept BOTH camelCase (`ocnName`) and snake_case (`ocn_name`)\n- **All values are strings** \u2014 even numeric fields. Always quote: `value: \"720\"` not `value: 720`\n- **GraphQL LIKE is case-sensitive (SQL)** \u2014 LERG data is stored UPPERCASE, so patterns must be uppercase: `%VERIZON%` not `%verizon%`. (The REST `like` operator is case-insensitive \u2014 this only applies to GraphQL.)\n\n**FilterInput:**\n```graphql\n{ field: \"ocnName\", op: LIKE, value: \"%VERIZON%\" } # partial match (UPPERCASE!)\n{ field: \"npa\", op: EQ, value: \"720\" } # exact match\n{ field: \"npa\", op: IN, values: [\"212\", \"646\", \"917\"] } # IN uses 'values' (plural), not 'value'\n```\n\nOperators: EQ, NE, GT, GTE, LT, LTE, LIKE, IN, IS_NULL, IS_NOT_NULL\n\n**Predefined relationships** (avoid N+1 \u2014 use these instead of separate queries):\n- `lerg6` \u2192 `carrier` (joins to lerg1 via OCN), `switchInfo` (\u2192 lerg7), `homingArrangements` (\u2192 lerg7Sha)\n- `lerg7` \u2192 `carrier` (\u2192 lerg1)\n- `lerg7Sha` \u2192 `tandemSwitch` (\u2192 lerg7)\n\n**Example \u2014 find all Verizon OCNs:**\n```graphql\n{\n lerg1(\n filters: [{ field: \"ocnName\", op: LIKE, value: \"%VERIZON%\" }]\n pagination: { limit: 10 }\n ) {\n ocnNum\n ocnName\n ocnState\n category\n }\n}\n```\n\n**Example \u2014 NPA-NXX with carrier and switch in one query:**\n```graphql\n{\n lerg6(\n filters: [{ field: \"npa\", op: EQ, value: \"303\" }, { field: \"nxx\", op: EQ, value: \"629\" }]\n pagination: { limit: 1 }\n ) {\n npa nxx ocn locName switch\n carrier { ocnNum ocnName ocnState }\n switchInfo { switch eqpType swCity swState }\n homingArrangements {\n shaIndicator hTrmDTdm\n tandemSwitch { switch swCity swState }\n }\n }\n}\n```\n\n**dynamicJoin** \u2014 for arbitrary cross-table SQL joins (returns raw JSON):\n```graphql\n{\n dynamicJoin(input: {\n table: \"lerg_6\"\n fields: [\"npa\", \"nxx\", \"ocn\", \"locName\"]\n filters: [{ field: \"locName\", op: LIKE, value: \"%DENVER%\" }]\n join: {\n table: \"lerg_1\"\n fields: [\"ocnName\", \"category\"]\n on: [{ leftField: \"ocn\", rightField: \"ocnNum\" }]\n joinType: \"INNER\"\n }\n pagination: { limit: 10 }\n })\n}\n```\nNote: dynamicJoin uses snake_case table IDs (lerg_6, lerg_1, lerg_7_sha) and returns raw PostgreSQL column names (UPPERCASE with spaces, e.g., `\"OCN_NAME\"`, `\"LOC NAME\"`, `\"EFF DATE\"`), NOT GraphQL camelCase.\n\n### LSMS GraphQL (`service=\"lsms\"`)\n\nThe LSMS GraphQL API is a **completely separate implementation** from LERG GraphQL. It has different query patterns, different field naming, and different schema design. Do NOT use LERG-style FilterInput syntax with LSMS.\n\n**5 tables:**\n\n| Table | ~Rows | Requires Filter? |\n|-------|-------|------------------|\n| subscriptionVersions | 514M | Yes (phoneNumber, lrn, or spid) |\n| numberBlocks | 751K | Yes (npanxxx, spid, or lrn) |\n| serviceProviders | 5.2K | No |\n| locationRoutingNumbers | 56K | No |\n| npanxx | 192K | No |\n\n**Query patterns (NOT FilterInput \u2014 uses typed named parameters):**\n```graphql\n# Single phone number lookup\n{ subscriptionVersion(phoneNumber: \"3036298301\") { phoneNumber lrn spid serviceProvider { name } } }\n\n# Paginated list by LRN (returns totalCount, hasMore)\n{ subscriptionVersionsByLrn(lrn: \"7207081999\", limit: 10) { totalCount hasMore items { phoneNumber spid } } }\n\n# Paginated list by SPID\n{ subscriptionVersionsBySpid(spid: \"567G\", limit: 10) { totalCount hasMore items { phoneNumber lrn } } }\n\n# Number block lookup (single)\n{ numberBlock(npanxxx: \"3035551\") { npanxxx lrn spid serviceProvider { name } } }\n\n# Number blocks by SPID or LRN (paginated \u2014 at least one filter required)\n{ numberBlocks(spid: \"567G\", limit: 10) { totalCount hasMore items { npanxxx lrn spid } } }\n\n# Single carrier lookup (note: composite PK \u2014 same SPID may exist in multiple regions)\n{ serviceProvider(spid: \"567G\") { spid name npacRegion status contactInfo } }\n\n# List carriers (paginated)\n{ serviceProviders(limit: 20) { spid name npacRegion } }\n\n# LRN metadata\n{ locationRoutingNumber(lrn: \"7207081999\") { lrn ocn regionId status switchInfo } }\n\n# NPA-NXX single lookup\n{ npanxx(npa: \"303\", nxx: \"629\") { npa nxx spid effectiveTimestamp serviceProvider { name } } }\n\n# NPA-NXX codes for a carrier (paginated)\n{ npanxxBySpid(spid: \"567G\", limit: 50) { npa nxx effectiveTimestamp } }\n\n# Database statistics\n{ lsmsStats { activeSubscriptionVersions activeNumberBlocks totalServiceProviders totalLocationRoutingNumbers activeNpanxx } }\n```\n\n**Relationships** (use DataLoader batching \u2014 no N+1):\n- subscriptionVersion \u2192 `serviceProvider`, `lrnMetadata`\n- numberBlock \u2192 `serviceProvider`, `lrnMetadata`\n- npanxx \u2192 `serviceProvider`\n\n**Safety limits:** max 1000 results, depth 5, complexity 200, 10-second statement timeout\n**Auto-filters:** Soft-deletable records filter to is_active = true automatically\n**Note:** Phone numbers/LRNs are strings (stored as BIGINT but GraphQL Int is 32-bit). SPIDs are auto-trimmed (stored as CHAR(4) with trailing spaces).\n**Note:** Service providers have a composite PK of (spid, npac_region) \u2014 the same SPID may appear in multiple NPAC regions.\n\n---\n\n## REST Paths for Direct API Access\n\nThe MCP tools wrap these HTTP endpoints. Use this table when calling the Telique API directly with `curl` or another HTTP client. Base URL: `https://api.telique.ringer.tel`. Authentication: `-H \"x-api-token: tlq_\u2026\"` (per-request header, never in query string).\n\n**Path forms:** the short `/v1/{service}/\u2026` paths below are the preferred form (since 2026-07-13). The older `/v1/telique/{service}/\u2026` paths route identically and remain fully supported for backwards compatibility \u2014 prepend `/telique` after `/v1` to any path in this table.\n\n| Tool | Method | Path | Notes |\n|------|--------|------|-------|\n| `lrn_lookup` | GET | `/v1/lrn/{phone_number}` | Add `?format=json` for structured response; default is `LRN;SPID` plain text |\n| `cnam_lookup` | GET | `/v1/cnam/{phone_number}` | Returns calling_name, presentation_indicator |\n| `dno_check` | GET | `/v1/dno/{phone_number}` | Add `?format=json` for details; default is `true`/`false` text |\n| `lrn_relationship_query` | GET | `/v1/lsms/list/{resource}?{filter}={value}` | `resource` \u2208 {phone_number, spid, lrn}; filter \u2208 {lrn, spid, phone_number}; exactly one filter |\n| `lerg_table_info` | GET | `/v1/lerg/tables` or `/v1/lerg/tables/{table_name}` | No args = list all tables |\n| `lerg_query` | GET | `/v1/lerg/{table_name}/{fields}/{query}` | Example: `/lerg/lerg_6/npa,nxx,ocn/npa=303&nxx=629` |\n| `lerg_complex_query` | POST | `/v1/lerg/query` | JSON body with table, fields, filters, join, limit, offset |\n| `lerg_tandem` | GET | `/v1/lerg/tandem?npa={npa}&nxx={nxx}` | Pre-joined tandem lookup |\n| `routelink_lookup` (ror) | GET | `/v1/ror/{crn}` | Responsible Organization for a toll-free number |\n| `routelink_lookup` (cic/cicror) | GET | `/v1/{cic\\|cicror}/{crn}/{ani}/{lata}` | CIC or CIC+ROR for a toll-free call |\n| `routelink_ror_query` | GET | `/v1/ror/{ror}/{tfns\\|cprs}` | List TFNs or CPRs for a ROR; paginated `?limit=&offset=` |\n| `routelink_cpr` | GET | `/v1/cpr/{crn}` | Call Processing Record; add `?expand=true` to inline templates |\n| `graphql_query` (lerg) | POST | `/v1/lerg/gql` | JSON body `{\"query\":\"...\"}`; GET returns GraphiQL playground HTML |\n| `graphql_query` (lsms) | POST | `/v1/lsms/gql` | JSON body `{\"query\":\"...\"}`; GET returns GraphiQL playground HTML |\n| `lookup_tn` | \u2014 | (composite) | Not a single endpoint \u2014 fans out to `/lrn/`, `/cnam/`, `/dno/`, `/lerg/\u2026` in parallel |\n\n**Note on RouteLink paths**: there is NO `/routelink/` segment. The public OpenAPI spec at `https://telique.ringer.tel/docs/api-reference` historically listed `/v1/telique/routelink/cpr/{crn}` etc. \u2014 those paths return 404. The real paths are bare (`/v1/cpr/{crn}`) as shown above.\n\n---\n\n## Key Telecom Concepts\n\n| Term | Definition |\n|------|-----------|\n| **LRN** | Location Routing Number \u2014 identifies the switch serving a ported number |\n| **SPID** | Service Provider ID \u2014 identifies the carrier that owns a number |\n| **OCN** | Operating Company Number \u2014 4-char carrier identifier (often same as SPID) |\n| **NPA** | Numbering Plan Area \u2014 3-digit area code |\n| **NXX** | Exchange code \u2014 next 3 digits after area code |\n| **LATA** | Local Access Transport Area \u2014 geographic region for call routing |\n| **CLLI** | Common Language Location Identifier \u2014 8-11 char switch/building code |\n| **CRN** | Call Routing Number \u2014 a toll-free number in RouteLink context |\n| **ROR/RespOrg** | Responsible Organization \u2014 entity managing a toll-free number's routing |\n| **CIC** | Carrier Identification Code \u2014 identifies which carrier handles a toll-free call |\n| **CPR** | Call Processing Record \u2014 routing decision tree for a toll-free number |\n| **Rate Center** | Geographic area defining local calling boundaries |\n| **Tandem** | A switching office that connects local switches to the long-distance network |\n| **Homing** | The relationship between a local switch and its tandem |\n\n---\n\n## Common Mistakes to Avoid\n\n1. **Never guess carrier names** \u2014 always query lerg_1 by OCN\n2. **Never skip the LRN dip** \u2014 ported TNs have different NPA-NXX than their LRN\n3. **Never look for tandem/switch data in LSMS** \u2014 LSMS has no infrastructure data\n4. **Never look for TN-level data in LERG** \u2014 LERG has no per-phone-number data\n5. **Never query LSMS subscriptionVersions without a filter** \u2014 514M rows will timeout\n6. **Always use the LRN's NPA-NXX** (not the TN's) for LERG routing lookups\n7. **GraphQL return fields must be camelCase** \u2014 `ocnName` not `ocn_name`, `locState` not `loc_state`\n8. **GraphQL LIKE patterns must be UPPERCASE** \u2014 LERG data is uppercase in PostgreSQL, so `%VERIZON%` works but `%verizon%` returns nothing. (REST `like` is case-insensitive \u2014 this only applies to GraphQL.)\n9. **IN operator uses `values` (plural)** \u2014 `{ field: \"npa\", op: IN, values: [\"212\", \"646\"] }` not `value`\n";
package/dist/knowledge.js CHANGED
@@ -172,7 +172,7 @@ The LRN API serves live NPAC porting data from an in-memory Judy Array store (50
172
172
 
173
173
  ### LRN Lookup (\`lrn_lookup\` tool)
174
174
 
175
- \`GET /v1/telique/lrn/{phone_number}?format=json\`
175
+ \`GET /v1/lrn/{phone_number}?format=json\`
176
176
 
177
177
  Returns the current LRN and carrier for a phone number. This is the fastest lookup — served from in-memory store, not PostgreSQL.
178
178
 
@@ -202,12 +202,12 @@ Query relationships between phone numbers, LRNs, and SPIDs from the LSMS Postgre
202
202
 
203
203
  | query_type | Endpoint | Description |
204
204
  |------------|----------|-------------|
205
- | \`phones_by_lrn\` | \`GET /v1/telique/lsms/list/phone_number?lrn={value}\` | All phone numbers for a given LRN |
206
- | \`phones_by_spid\` | \`GET /v1/telique/lsms/list/phone_number?spid={value}\` | All phone numbers for a given SPID |
207
- | \`spid_by_lrn\` | \`GET /v1/telique/lsms/list/spid?lrn={value}\` | All SPIDs associated with a given LRN |
208
- | \`spid_by_phone\` | \`GET /v1/telique/lsms/list/spid?phone_number={value}\` | All SPIDs for a given phone number |
209
- | \`lrn_by_spid\` | \`GET /v1/telique/lsms/list/lrn?spid={value}\` | All LRNs for a given SPID |
210
- | \`lrn_by_phone\` | \`GET /v1/telique/lsms/list/lrn?phone_number={value}\` | All LRNs for a given phone number |
205
+ | \`phones_by_lrn\` | \`GET /v1/lsms/list/phone_number?lrn={value}\` | All phone numbers for a given LRN |
206
+ | \`phones_by_spid\` | \`GET /v1/lsms/list/phone_number?spid={value}\` | All phone numbers for a given SPID |
207
+ | \`spid_by_lrn\` | \`GET /v1/lsms/list/spid?lrn={value}\` | All SPIDs associated with a given LRN |
208
+ | \`spid_by_phone\` | \`GET /v1/lsms/list/spid?phone_number={value}\` | All SPIDs for a given phone number |
209
+ | \`lrn_by_spid\` | \`GET /v1/lsms/list/lrn?spid={value}\` | All LRNs for a given SPID |
210
+ | \`lrn_by_phone\` | \`GET /v1/lsms/list/lrn?phone_number={value}\` | All LRNs for a given phone number |
211
211
 
212
212
  **Constraints:**
213
213
  - Exactly ONE query parameter per request (multiple parameters return a validation error)
@@ -440,25 +440,27 @@ The LSMS GraphQL API is a **completely separate implementation** from LERG Graph
440
440
 
441
441
  The MCP tools wrap these HTTP endpoints. Use this table when calling the Telique API directly with \`curl\` or another HTTP client. Base URL: \`https://api.telique.ringer.tel\`. Authentication: \`-H "x-api-token: tlq_…"\` (per-request header, never in query string).
442
442
 
443
+ **Path forms:** the short \`/v1/{service}/…\` paths below are the preferred form (since 2026-07-13). The older \`/v1/telique/{service}/…\` paths route identically and remain fully supported for backwards compatibility — prepend \`/telique\` after \`/v1\` to any path in this table.
444
+
443
445
  | Tool | Method | Path | Notes |
444
446
  |------|--------|------|-------|
445
- | \`lrn_lookup\` | GET | \`/v1/telique/lrn/{phone_number}\` | Add \`?format=json\` for structured response; default is \`LRN;SPID\` plain text |
446
- | \`cnam_lookup\` | GET | \`/v1/telique/cnam/{phone_number}\` | Returns calling_name, presentation_indicator |
447
- | \`dno_check\` | GET | \`/v1/telique/dno/{phone_number}\` | Add \`?format=json\` for details; default is \`true\`/\`false\` text |
448
- | \`lrn_relationship_query\` | GET | \`/v1/telique/lsms/list/{resource}?{filter}={value}\` | \`resource\` ∈ {phone_number, spid, lrn}; filter ∈ {lrn, spid, phone_number}; exactly one filter |
449
- | \`lerg_table_info\` | GET | \`/v1/telique/lerg/tables\` or \`/v1/telique/lerg/tables/{table_name}\` | No args = list all tables |
450
- | \`lerg_query\` | GET | \`/v1/telique/lerg/{table_name}/{fields}/{query}\` | Example: \`/lerg/lerg_6/npa,nxx,ocn/npa=303&nxx=629\` |
451
- | \`lerg_complex_query\` | POST | \`/v1/telique/lerg/query\` | JSON body with table, fields, filters, join, limit, offset |
452
- | \`lerg_tandem\` | GET | \`/v1/telique/lerg/tandem?npa={npa}&nxx={nxx}\` | Pre-joined tandem lookup |
453
- | \`routelink_lookup\` (ror) | GET | \`/v1/telique/ror/{crn}\` | Responsible Organization for a toll-free number |
454
- | \`routelink_lookup\` (cic/cicror) | GET | \`/v1/telique/{cic\\|cicror}/{crn}/{ani}/{lata}\` | CIC or CIC+ROR for a toll-free call |
455
- | \`routelink_ror_query\` | GET | \`/v1/telique/ror/{ror}/{tfns\\|cprs}\` | List TFNs or CPRs for a ROR; paginated \`?limit=&offset=\` |
456
- | \`routelink_cpr\` | GET | \`/v1/telique/cpr/{crn}\` | Call Processing Record; add \`?expand=true\` to inline templates |
457
- | \`graphql_query\` (lerg) | POST | \`/v1/telique/lerg/gql\` | JSON body \`{"query":"..."}\`; GET returns GraphiQL playground HTML |
458
- | \`graphql_query\` (lsms) | POST | \`/v1/telique/lsms/gql\` | JSON body \`{"query":"..."}\`; GET returns GraphiQL playground HTML |
447
+ | \`lrn_lookup\` | GET | \`/v1/lrn/{phone_number}\` | Add \`?format=json\` for structured response; default is \`LRN;SPID\` plain text |
448
+ | \`cnam_lookup\` | GET | \`/v1/cnam/{phone_number}\` | Returns calling_name, presentation_indicator |
449
+ | \`dno_check\` | GET | \`/v1/dno/{phone_number}\` | Add \`?format=json\` for details; default is \`true\`/\`false\` text |
450
+ | \`lrn_relationship_query\` | GET | \`/v1/lsms/list/{resource}?{filter}={value}\` | \`resource\` ∈ {phone_number, spid, lrn}; filter ∈ {lrn, spid, phone_number}; exactly one filter |
451
+ | \`lerg_table_info\` | GET | \`/v1/lerg/tables\` or \`/v1/lerg/tables/{table_name}\` | No args = list all tables |
452
+ | \`lerg_query\` | GET | \`/v1/lerg/{table_name}/{fields}/{query}\` | Example: \`/lerg/lerg_6/npa,nxx,ocn/npa=303&nxx=629\` |
453
+ | \`lerg_complex_query\` | POST | \`/v1/lerg/query\` | JSON body with table, fields, filters, join, limit, offset |
454
+ | \`lerg_tandem\` | GET | \`/v1/lerg/tandem?npa={npa}&nxx={nxx}\` | Pre-joined tandem lookup |
455
+ | \`routelink_lookup\` (ror) | GET | \`/v1/ror/{crn}\` | Responsible Organization for a toll-free number |
456
+ | \`routelink_lookup\` (cic/cicror) | GET | \`/v1/{cic\\|cicror}/{crn}/{ani}/{lata}\` | CIC or CIC+ROR for a toll-free call |
457
+ | \`routelink_ror_query\` | GET | \`/v1/ror/{ror}/{tfns\\|cprs}\` | List TFNs or CPRs for a ROR; paginated \`?limit=&offset=\` |
458
+ | \`routelink_cpr\` | GET | \`/v1/cpr/{crn}\` | Call Processing Record; add \`?expand=true\` to inline templates |
459
+ | \`graphql_query\` (lerg) | POST | \`/v1/lerg/gql\` | JSON body \`{"query":"..."}\`; GET returns GraphiQL playground HTML |
460
+ | \`graphql_query\` (lsms) | POST | \`/v1/lsms/gql\` | JSON body \`{"query":"..."}\`; GET returns GraphiQL playground HTML |
459
461
  | \`lookup_tn\` | — | (composite) | Not a single endpoint — fans out to \`/lrn/\`, \`/cnam/\`, \`/dno/\`, \`/lerg/…\` in parallel |
460
462
 
461
- **Note on RouteLink paths**: there is NO \`/routelink/\` segment. The public OpenAPI spec at \`https://telique.ringer.tel/docs/api-reference\` historically listed \`/v1/telique/routelink/cpr/{crn}\` etc. — those paths return 404. The real paths are bare (\`/v1/telique/cpr/{crn}\`) as shown above.
463
+ **Note on RouteLink paths**: there is NO \`/routelink/\` segment. The public OpenAPI spec at \`https://telique.ringer.tel/docs/api-reference\` historically listed \`/v1/telique/routelink/cpr/{crn}\` etc. — those paths return 404. The real paths are bare (\`/v1/cpr/{crn}\`) as shown above.
462
464
 
463
465
  ---
464
466
 
package/dist/setup.js CHANGED
@@ -365,7 +365,7 @@ async function validateToken(token) {
365
365
  apiToken: token,
366
366
  requestTimeoutMs: 10000,
367
367
  });
368
- const result = await client.get("/v1/telique/lerg/tables");
368
+ const result = await client.get("/v1/lerg/tables");
369
369
  return (typeof result === "object" && result !== null && !("_error" in result));
370
370
  }
371
371
  catch {
@@ -8,7 +8,7 @@ export function registerCnamTools(server, client) {
8
8
  .regex(/^\d{10,15}$/)
9
9
  .describe("10-15 digit phone number to look up"),
10
10
  }, READ_ONLY_ANNOTATIONS, async ({ phone_number }) => {
11
- const result = await client.get(`/v1/telique/cnam/${phone_number}`);
11
+ const result = await client.get(`/v1/cnam/${phone_number}`);
12
12
  return formatResponse(result);
13
13
  });
14
14
  }
@@ -12,16 +12,16 @@ export function registerCompositeTools(server, client) {
12
12
  const nxx = phone_number.substring(3, 6);
13
13
  const [lrn, cnam, dno, lerg] = await Promise.all([
14
14
  client
15
- .get(`/v1/telique/lrn/${phone_number}`, { format: "json" })
15
+ .get(`/v1/lrn/${phone_number}`, { format: "json" })
16
16
  .catch((err) => ({ _error: true, message: err.message })),
17
17
  client
18
- .get(`/v1/telique/cnam/${phone_number}`)
18
+ .get(`/v1/cnam/${phone_number}`)
19
19
  .catch((err) => ({ _error: true, message: err.message })),
20
20
  client
21
- .get(`/v1/telique/dno/${phone_number}`, { format: "json" })
21
+ .get(`/v1/dno/${phone_number}`, { format: "json" })
22
22
  .catch((err) => ({ _error: true, message: err.message })),
23
23
  client
24
- .get(`/v1/telique/lerg/lerg_6/npa,nxx,loc_name,loc_state,lata,lata_name,ocn,switch,rc_abbre,rc_type/npa=${npa}%26nxx=${nxx}`, { limit: 5 })
24
+ .get(`/v1/lerg/lerg_6/npa,nxx,loc_name,loc_state,lata,lata_name,ocn,switch,rc_abbre,rc_type/npa=${npa}%26nxx=${nxx}`, { limit: 5 })
25
25
  .catch((err) => ({ _error: true, message: err.message })),
26
26
  ]);
27
27
  const consolidated = {
@@ -17,8 +17,8 @@ LERG (service='lerg'): Static telecom reference. Uses FilterInput with operators
17
17
  .describe("Optional GraphQL variables"),
18
18
  }, READ_ONLY_ANNOTATIONS, async ({ service, query, variables }) => {
19
19
  const path = service === "lsms"
20
- ? "/v1/telique/lsms/gql"
21
- : "/v1/telique/lerg/gql";
20
+ ? "/v1/lsms/gql"
21
+ : "/v1/lerg/gql";
22
22
  const body = { query };
23
23
  if (variables)
24
24
  body.variables = variables;
@@ -38,10 +38,10 @@ export function registerLergTools(server, client) {
38
38
  .describe("Specific table name (e.g. lerg_1, lerg_6, lerg_7_sha). Omit to list all tables."),
39
39
  }, READ_ONLY_ANNOTATIONS, async ({ table_name }) => {
40
40
  if (table_name) {
41
- const result = await client.get(`/v1/telique/lerg/tables/${table_name}`);
41
+ const result = await client.get(`/v1/lerg/tables/${table_name}`);
42
42
  return formatResponse(result);
43
43
  }
44
- const result = await client.get("/v1/telique/lerg/tables");
44
+ const result = await client.get("/v1/lerg/tables");
45
45
  return formatResponse(result);
46
46
  });
47
47
  server.tool("lerg_query", "Query any LERG table by field values. Common queries: carrier by OCN (lerg_1, fields: ocn_num,ocn_name,ocn_state), NPA-NXX info (lerg_6, fields: npa,nxx,loc_name,ocn,switch,lata), switch details (lerg_7, fields: switch,ocn,aocn), LRN registry (lerg_12, fields: lrn,lata,switch,ocn). Filter format: field=value, multiple filters joined with & (e.g. npa=303&nxx=629).", {
@@ -68,7 +68,7 @@ export function registerLergTools(server, client) {
68
68
  }, READ_ONLY_ANNOTATIONS, async ({ table_name, fields, query, limit, offset }) => {
69
69
  // Encode & as %26 so multi-filters stay in the path segment
70
70
  const encodedQuery = query.replace(/&/g, "%26");
71
- const result = await client.get(`/v1/telique/lerg/${table_name}/${fields}/${encodedQuery}`, { limit, offset });
71
+ const result = await client.get(`/v1/lerg/${table_name}/${fields}/${encodedQuery}`, { limit, offset });
72
72
  return formatResponse(result);
73
73
  });
74
74
  server.tool("lerg_complex_query", "Execute a complex LERG query with JOINs across multiple tables. Supports filter operators: eq, ne, gt, gte, lt, lte, like, in, isnull, isnotnull. Use this when you need to combine data from different LERG tables, such as joining NPA-NXX (lerg_6) with carrier info (lerg_1) via OCN.", {
@@ -139,7 +139,7 @@ export function registerLergTools(server, client) {
139
139
  body.fields = fields;
140
140
  if (join)
141
141
  body.join = join;
142
- const result = await client.post("/v1/telique/lerg/query", body);
142
+ const result = await client.post("/v1/lerg/query", body);
143
143
  return formatResponse(result);
144
144
  });
145
145
  server.tool("lerg_tandem", "Look up tandem routing information. Query by NPA+NXX, switch CLLI, tandem CLLI, or carrier name pattern. Returns tandem switch, OCN, LATA, and routing path via SQL JOINs across lerg_6, lerg_7_sha, and lerg_1.", {
@@ -193,7 +193,7 @@ export function registerLergTools(server, client) {
193
193
  params.tandem = tandem;
194
194
  if (name)
195
195
  params.name = name;
196
- const result = await client.get("/v1/telique/lerg/tandem", params);
196
+ const result = await client.get("/v1/lerg/tandem", params);
197
197
  return formatResponse(result);
198
198
  });
199
199
  }
package/dist/tools/lrn.js CHANGED
@@ -8,7 +8,7 @@ export function registerLrnTools(server, client) {
8
8
  .regex(/^\d{10}$/)
9
9
  .describe("10-digit US phone number"),
10
10
  }, READ_ONLY_ANNOTATIONS, async ({ phone_number }) => {
11
- const result = await client.get(`/v1/telique/lrn/${phone_number}`, {
11
+ const result = await client.get(`/v1/lrn/${phone_number}`, {
12
12
  format: "json",
13
13
  });
14
14
  return formatResponse(result);
@@ -40,7 +40,7 @@ export function registerLrnTools(server, client) {
40
40
  if (!route) {
41
41
  return errorResult(`Unknown query_type: ${query_type}`);
42
42
  }
43
- const result = await client.get(`/v1/telique/lsms/list/${route.resource}`, { [route.param]: value });
43
+ const result = await client.get(`/v1/lsms/list/${route.resource}`, { [route.param]: value });
44
44
  return formatResponse(result);
45
45
  });
46
46
  server.tool("dno_check", "Check if a phone number is on the Do Not Originate (DNO) list. DNO numbers should never appear as a caller ID because they belong to entities that only receive calls (e.g., IRS, major banks). A match indicates potential caller ID spoofing. Supports prefix matching (3, 6, 7, or 10 digit patterns).", {
@@ -49,7 +49,7 @@ export function registerLrnTools(server, client) {
49
49
  .regex(/^\d{10}$/)
50
50
  .describe("10-digit US phone number to check"),
51
51
  }, READ_ONLY_ANNOTATIONS, async ({ phone_number }) => {
52
- const result = await client.get(`/v1/telique/dno/${phone_number}`, {
52
+ const result = await client.get(`/v1/dno/${phone_number}`, {
53
53
  format: "json",
54
54
  });
55
55
  return formatResponse(result);
@@ -27,10 +27,10 @@ export function registerRoutelinkTools(server, client) {
27
27
  }
28
28
  let path;
29
29
  if (lookup_type === "ror") {
30
- path = `/v1/telique/ror/${crn}`;
30
+ path = `/v1/ror/${crn}`;
31
31
  }
32
32
  else {
33
- path = `/v1/telique/${lookup_type}/${crn}/${ani}/${lata}`;
33
+ path = `/v1/${lookup_type}/${crn}/${ani}/${lata}`;
34
34
  }
35
35
  const result = await client.get(path, { format: "json" });
36
36
  return formatResponse(result);
@@ -57,7 +57,7 @@ export function registerRoutelinkTools(server, client) {
57
57
  .default(0)
58
58
  .describe("Pagination offset (default 0)"),
59
59
  }, READ_ONLY_ANNOTATIONS, async ({ ror, resource_type, limit, offset }) => {
60
- const result = await client.get(`/v1/telique/ror/${ror}/${resource_type}`, { format: "json", limit, offset });
60
+ const result = await client.get(`/v1/ror/${ror}/${resource_type}`, { format: "json", limit, offset });
61
61
  return formatResponse(result);
62
62
  });
63
63
  server.tool("routelink_cpr", "Retrieve the full Call Processing Record (CPR) for a toll-free number. A CPR is a routing decision tree that determines how calls are routed based on LATA, NPA, NXX, ANI, DAY_OF_WEEK, TIME_OF_DAY, PERCENT, STATE, etc. Returns the CPR structure, SHA1 hash, ROR, and optionally expanded template references.", {
@@ -70,9 +70,7 @@ export function registerRoutelinkTools(server, client) {
70
70
  .default(true)
71
71
  .describe("Recursively resolve and inline template decision trees (default true)"),
72
72
  }, READ_ONLY_ANNOTATIONS, async ({ crn, expand }) => {
73
- // NOTE: /v1/telique/cpr/* path pending frontend URL map addition.
74
- // Falls back to /cpr/ which routes to routelink via default backend.
75
- const result = await client.get(`/v1/telique/cpr/${crn}`, {
73
+ const result = await client.get(`/v1/cpr/${crn}`, {
76
74
  format: "json",
77
75
  expand: expand ? "true" : "false",
78
76
  });
package/openapi.yaml CHANGED
@@ -7,6 +7,10 @@ info:
7
7
  CNAM (Caller Name) identification, LERG (Local Exchange Routing Guide) infrastructure data,
8
8
  toll-free number routing via RouteLink, and GraphQL interfaces for advanced queries.
9
9
 
10
+ The short `/v1/{service}/…` paths documented here are the preferred form (since
11
+ 2026-07-13). The older `/v1/telique/{service}/…` paths route identically and remain
12
+ fully supported for backwards compatibility.
13
+
10
14
  ## Authentication
11
15
 
12
16
  All endpoints require an API token passed via the `x-api-token` header.
@@ -56,7 +60,7 @@ tags:
56
60
 
57
61
  paths:
58
62
  # ── LRN ──────────────────────────────────────────────────────────
59
- /v1/telique/lrn/{phone_number}:
63
+ /v1/lrn/{phone_number}:
60
64
  get:
61
65
  operationId: lrnLookup
62
66
  tags: [LRN]
@@ -91,7 +95,7 @@ paths:
91
95
  '429':
92
96
  description: Rate limit exceeded
93
97
 
94
- /v1/telique/lsms/list/{resource}:
98
+ /v1/lsms/list/{resource}:
95
99
  get:
96
100
  operationId: lrnRelationshipQuery
97
101
  tags: [LRN]
@@ -137,7 +141,7 @@ paths:
137
141
  count:
138
142
  type: integer
139
143
 
140
- /v1/telique/dno/{phone_number}:
144
+ /v1/dno/{phone_number}:
141
145
  get:
142
146
  operationId: dnoCheck
143
147
  tags: [LRN]
@@ -169,7 +173,7 @@ paths:
169
173
  source: 'FTC'
170
174
 
171
175
  # ── CNAM ─────────────────────────────────────────────────────────
172
- /v1/telique/cnam/{phone_number}:
176
+ /v1/cnam/{phone_number}:
173
177
  get:
174
178
  operationId: cnamLookup
175
179
  tags: [CNAM]
@@ -200,7 +204,7 @@ paths:
200
204
  presentation_indicator: 'allowed'
201
205
 
202
206
  # ── LERG ─────────────────────────────────────────────────────────
203
- /v1/telique/lerg/tables:
207
+ /v1/lerg/tables:
204
208
  get:
205
209
  operationId: lergListTables
206
210
  tags: [LERG]
@@ -219,7 +223,7 @@ paths:
219
223
  items:
220
224
  $ref: '#/components/schemas/LergTableInfo'
221
225
 
222
- /v1/telique/lerg/tables/{table_name}:
226
+ /v1/lerg/tables/{table_name}:
223
227
  get:
224
228
  operationId: lergTableInfo
225
229
  tags: [LERG]
@@ -243,7 +247,7 @@ paths:
243
247
  '404':
244
248
  description: Table not found
245
249
 
246
- /v1/telique/lerg/{table_name}/{fields}/{query}:
250
+ /v1/lerg/{table_name}/{fields}/{query}:
247
251
  get:
248
252
  operationId: lergQuery
249
253
  tags: [LERG]
@@ -300,7 +304,7 @@ paths:
300
304
  schema:
301
305
  $ref: '#/components/schemas/LergQueryResponse'
302
306
 
303
- /v1/telique/lerg/query:
307
+ /v1/lerg/query:
304
308
  post:
305
309
  operationId: lergComplexQuery
306
310
  tags: [LERG]
@@ -344,7 +348,7 @@ paths:
344
348
  schema:
345
349
  $ref: '#/components/schemas/LergQueryResponse'
346
350
 
347
- /v1/telique/lerg/tandem:
351
+ /v1/lerg/tandem:
348
352
  get:
349
353
  operationId: lergTandem
350
354
  tags: [LERG]
@@ -405,7 +409,7 @@ paths:
405
409
  $ref: '#/components/schemas/LergQueryResponse'
406
410
 
407
411
  # ── RouteLink ────────────────────────────────────────────────────
408
- /v1/telique/ror/{crn}:
412
+ /v1/ror/{crn}:
409
413
  get:
410
414
  operationId: routelinkRorLookup
411
415
  tags: [RouteLink]
@@ -433,7 +437,7 @@ paths:
433
437
  crn: '8005551234'
434
438
  ror: 'ATX01'
435
439
 
436
- /v1/telique/{lookup_type}/{crn}/{ani}/{lata}:
440
+ /v1/{lookup_type}/{crn}/{ani}/{lata}:
437
441
  get:
438
442
  operationId: routelinkCicLookup
439
443
  tags: [RouteLink]
@@ -486,7 +490,7 @@ paths:
486
490
  cic: '0288'
487
491
  ror: 'ATX01'
488
492
 
489
- /v1/telique/ror/{ror}/{resource_type}:
493
+ /v1/ror/{ror}/{resource_type}:
490
494
  get:
491
495
  operationId: routelinkRorQuery
492
496
  tags: [RouteLink]
@@ -541,7 +545,7 @@ paths:
541
545
  count:
542
546
  type: integer
543
547
 
544
- /v1/telique/cpr/{crn}:
548
+ /v1/cpr/{crn}:
545
549
  get:
546
550
  operationId: routelinkCpr
547
551
  tags: [RouteLink]
@@ -576,7 +580,7 @@ paths:
576
580
  $ref: '#/components/schemas/CprResponse'
577
581
 
578
582
  # ── GraphQL ──────────────────────────────────────────────────────
579
- /v1/telique/lsms/gql:
583
+ /v1/lsms/gql:
580
584
  post:
581
585
  operationId: graphqlLsms
582
586
  tags: [GraphQL]
@@ -608,7 +612,7 @@ paths:
608
612
  schema:
609
613
  $ref: '#/components/schemas/GraphQLResponse'
610
614
 
611
- /v1/telique/lerg/gql:
615
+ /v1/lerg/gql:
612
616
  post:
613
617
  operationId: graphqlLerg
614
618
  tags: [GraphQL]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telique-mcp",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "MCP server for Telique telecom APIs (RouteLink, LRN, CNAM, LERG)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",