MCP developer reference
Connecting Claude, ChatGPT, Gemini or another AI app? Follow the setup page instead. It has the current steps for every client, with copy buttons, and nothing on this page is needed for that.
This page is for developers: calling the Directories.ai MCP server from your own code, a gateway, or a workplace AI platform that needs OAuth details.
The basics
- Server URL:
https://directories.ai/mcp - Auth for apps: OAuth 2.1. The client opens a "Sign in to Directories.ai" page and you approve it for one organization.
- Auth for code and local clients:
Authorization: Bearer <API key>. Create the key in Dashboard → Settings → API Keys. - Client ID and secret: For platforms that can't register themselves, such as Gemini Enterprise: the same page, under App credentials.
The server speaks standard MCP: JSON-RPC 2.0 over Streamable HTTP, protocol
versions 2024-11-05, 2025-03-26, 2025-06-18 and 2025-11-25, with OAuth
discovery. Any MCP-compliant client or SDK works without Directories.ai-specific
code.
Who can use it
The MCP works for accounts with at least one directory on an active plan, a
trial, or a lifetime deal. Other accounts can still connect, but every tool
except create_directory returns a message with a link to start a plan.
OAuth endpoints
Most clients discover these on their own. Platforms that ask for them:
- Authorization URL:
https://directories.ai/oauth/authorize - Token URL:
https://directories.ai/api/oauth/token - Dynamic client registration:
https://directories.ai/api/oauth/register - Revocation:
https://directories.ai/api/oauth/revoke - Scopes:
mcp, plusoffline_accessfor refresh tokens - PKCE: Required (S256)
Apps connected with OAuth are listed, and can be disconnected, under Dashboard → Settings → API Keys.
Clients that use an API key
Clients without OAuth (many local-model setups, a LiteLLM or OpenRouter-fronted gateway, CI jobs) send the key in a header. Most read this JSON:
{
"mcpServers": {
"directories-ai": {
"type": "http",
"url": "https://directories.ai/mcp",
"headers": {
"Authorization": "Bearer ${DIRECTORIES_AI_API_KEY}"
}
}
}
}
Keep the key in an environment variable rather than in the file. A model router only picks which model answers; the MCP connection lives in the app or gateway in front of it.
Calling it from your own code
Two methods cover most integrations:
tools/listreturns the available tools and their input schemas.tools/callruns one, with{ name, arguments }.
TypeScript, plain fetch
async function callTool(name: string, args: Record<string, unknown> = {}) {
const response = await fetch('https://directories.ai/mcp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.DIRECTORIES_AI_API_KEY}`,
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: { name, arguments: args },
}),
});
const { result } = await response.json();
return JSON.parse(result.content[0].text);
}
const directories = await callTool('list_directories');
const listings = await callTool('list_listings', { directory_id: '<directory id>' });
TypeScript, official MCP SDK
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(new URL('https://directories.ai/mcp'), {
requestInit: { headers: { Authorization: `Bearer ${process.env.DIRECTORIES_AI_API_KEY}` } },
});
const client = new Client({ name: 'my-app', version: '1.0.0' });
await client.connect(transport);
const directories = await client.callTool({ name: 'list_directories', arguments: {} });
Python, official MCP SDK
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async with streamablehttp_client(
"https://directories.ai/mcp",
headers={"Authorization": f"Bearer {os.environ['DIRECTORIES_AI_API_KEY']}"},
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
directories = await session.call_tool("list_directories", {})
listings = await session.call_tool("list_listings", {"directory_id": "<directory id>"})
Gemini API, in your own app
The Google Gen AI SDK accepts an MCP session as a tool, so Gemini models call Directories.ai tools directly:
from google import genai
from google.genai import types
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
client = genai.Client() # GEMINI_API_KEY from the environment
async with streamablehttp_client(
"https://directories.ai/mcp",
headers={"Authorization": "Bearer <your Directories.ai API key>"},
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
response = await client.aio.models.generate_content(
model="gemini-2.5-flash",
contents="List my directories and tell me which one needs attention.",
config=types.GenerateContentConfig(tools=[session]),
)
print(response.text)
The same pattern works with any model API whose SDK supports MCP.
What's callable
Tools cover these areas:
- Directories, settings and AI configuration
- Listings, categories, search and duplicate checks
- Sourcing real businesses, imports from your own database or another directory platform
- Content: articles, FAQs, pages, events and the knowledge base
- Claims, claim outreach and cold-email lists
- Paid listings, checkout and memberships
- Email updates to people who already have an account
- Freshness checks, AI visibility tracking, backlinks and crawler access
- Social posts, analytics and embed codes
- Tasks and playbooks
- Proposed code changes as pull requests
Call tools/list on your own connection for the exact current set and its
schemas. It's the source of truth and grows as the server does.
Guided workflows ("playbooks") such as SEO and AI-visibility audits, content
briefs, link-building outreach and competitor research are available as the
list_playbooks and get_playbook tools, so they work in every client. Clients
with a prompt menu also get them as MCP prompts: ranking_best_practices_audit,
ai_era_design_review and run_playbook.
What's deliberately not callable
These never go through the server, however a request is phrased:
- Reading mail-provider keys, model API keys or database credentials
- Creating or reading your organization's API key, or minting any other credential
- Changing billing or a subscription
- Adding, removing or changing team members' access
- Changing a custom domain or listing slugs
- Pushing directly to a live site. Code changes only arrive as a pull request for you to review.
See the trust page for the full boundary.
Troubleshooting
- Every tool returns a "start a plan" message: No directory on the account has an active plan yet. See "Who can use it" above.
401 Unauthorized: Missing, invalid or expired token. OAuth clients refresh on their own; if it persists, disconnect and reconnect. For an API key, check it's active in Dashboard → Settings → API Keys.403mentioning embed keys: Embed keys are for public site scripts and don't work here. Use an organization API key or OAuth.400 Bad Request: A required argument is missing or has the wrong type. Check that tool's schema intools/list.404in a tool result: Thedirectory_idorlisting_iddoesn't exist or belongs to another organization.429 Too Many Requests: Rate limited. Retry with exponential backoff.- Connector adds but shows no tools: Some clients need the connector turned on in each conversation.
For help, contact support@directories.ai.