Connect any MCP client to the Shamela library
Connect the Shamela MCP server (Streamable HTTP, no key) from the TypeScript SDK, mcp-remote, MCP Inspector, curl or Python; avoid three setup traps.
Cette page n’est pas encore traduite — version anglaise affichée.
Sur cette page
The server is a plain remote MCP endpoint. Any client that speaks the Streamable HTTP transport can use it, whether or not it appears in a list of supported apps. The ready-made steps for ChatGPT, Claude, Claude Code, Gemini CLI, Cursor, VS Code and Copilot are in Getting started. This page is for everything else: SDKs, scripts, desktop apps that only run local programs, and debugging a connection that will not come up.
https://qurangallery.com/mcp/shamelaWhat the endpoint is
| Property | Value |
|---|---|
| Transport | Streamable HTTP. Every message is a POST with a JSON-RPC body |
| Not supported | SSE-only clients (the old HTTP+SSE transport), stdio, GET event streams. A GET with Accept: text/event-stream returns 405 |
| State | None. The server issues no session id, so each request stands alone |
| Replies | A single JSON object, Content-Type: application/json |
| Protocol versions | 2025-11-25 and 2025-06-18 |
| Authentication | None. An optional Authorization: Bearer qg_sk_… raises the limits |
| CORS | Open (Access-Control-Allow-Origin: *), so a browser client can call it |
A GET with Accept: application/json returns a small JSON description of the endpoint, which is handy for checking that a URL is the right one.
The three traps
1. Use the full path. The endpoint is /mcp/shamela. The address /mcp is a web page. A POST to it is redirected (308) to /mcp/, which is the web page. That address answers a POST with 405 Method Not Allowed, or with HTML if the client turns the request into a GET, so the client never receives a JSON-RPC reply.
2. Do not leave a placeholder in the Authorization header. The server checks any bearer token it is sent, so a keyless connection that carries a header such as Bearer qg_sk_your_key_here is rejected with HTTP 401 and -32001, “That API key is not valid.” Either send a real key or send no Authorization header at all. A completely empty header is ignored, but Bearer with nothing after it, which is what an unset environment variable in a header template produces, is rejected with the same 401.
3. Use a client that speaks Streamable HTTP. A client configured for the older SSE transport will get a 405 on its first request. Switch it to http or streamable-http, or put mcp-remote in front of it (below).
TypeScript or JavaScript SDK
With the official @modelcontextprotocol/sdk package:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const client = new Client({ name: 'example', version: '1.0.0' });
await client.connect(
new StreamableHTTPClientTransport(new URL('https://qurangallery.com/mcp/shamela'))
);
const { tools } = await client.listTools();
console.log(tools.length, tools[0].name); // 14 shamela_search_library
const result = await client.callTool({
name: 'shamela_search_library',
arguments: { query: 'إنما الأعمال بالنيات', scope: 'hadith-primary' }
});
const hit = result.structuredContent.passages[0];
console.log(hit.book, hit.printedPage, hit.matchedIn, hit.sourceUrl);
await client.close();This snippet was run on 2026-11-01 with @modelcontextprotocol/sdk 1.32.2, the latest 1.x release that day; it printed 14 shamela_search_library and the first passage’s book, printed page 5/ 305, body and source link. (The SDK also publishes a 2.x line as @modelcontextprotocol/client; the code above is the 1.x API.) The three curated tools declare an outputSchema, so structuredContent validates against it and passages is typed. To send a key, pass headers to the transport: new StreamableHTTPClientTransport(url, { requestInit: { headers: { Authorization: 'Bearer qg_sk_your_key_here' } } }), replacing the placeholder with your own key.
Desktop apps that only run local programs: mcp-remote
Some clients can launch a local command but cannot connect to a URL. mcp-remote is a small bridge that runs locally and talks to the remote server for them. For Claude Desktop’s configuration file, or any client that uses the same mcpServers format:
{
"mcpServers": {
"qurangallery-shamela": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://qurangallery.com/mcp/shamela"]
}
}
}It needs Node.js installed. Claude Desktop can also add the URL directly as a custom connector, which needs no bridge: see Claude.
MCP Inspector
To see the raw tool list and call tools by hand:
npx @modelcontextprotocol/inspector --cli https://qurangallery.com/mcp/shamela
--transport http --method tools/listThe CLI form above was run on 2026-11-01 with @modelcontextprotocol/inspector 2.13.0 and returned the tool list. For the web interface, run npx @modelcontextprotocol/inspector with no arguments, choose the transport Streamable HTTP and paste the URL.
curl, or any HTTP library
There is nothing to negotiate. Send the JSON-RPC message with both content types in Accept:
curl -s https://qurangallery.com/mcp/shamela
-H 'Content-Type: application/json'
-H 'Accept: application/json, text/event-stream'
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'The same call from Python’s standard library:
import json, urllib.request
def call(method, params=None, id=1):
req = urllib.request.Request(
'https://qurangallery.com/mcp/shamela',
data=json.dumps({'jsonrpc': '2.0', 'id': id, 'method': method, 'params': params or {}}).encode(),
headers={'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream'},
)
return json.load(urllib.request.urlopen(req))
tools = call('tools/list')['result']['tools']
hit = call('tools/call', {
'name': 'shamela_search_library',
'arguments': {'query': 'إنما الأعمال بالنيات', 'scope': 'hadith-primary'},
})['result']['structuredContent']['passages'][0]
print(len(tools), hit['book'], hit['printedPage'], hit['matchedIn'])A message that expects no reply, such as notifications/initialized, is answered with HTTP 202 and an empty body.
Limits that matter to a script
Keyless use allows 10 tool calls a minute and 200 a day per IP address. Connecting and listing tools are not tool calls, so keyless they do not use that allowance; they have a flood ceiling of 60 requests a minute per IP. With a key they count toward the key’s 60. A 429 carries Retry-After and RateLimit-* headers. With a free key the allowance is 60 tool calls a minute. If the key service cannot be reached at that moment, a request that carries a key gets HTTP 503, -32002 and Retry-After: 30: retry it, and do not read it as a bad key. The full table is in Limits and errors.
If a client connects but shows no tools
- The URL ends in
/mcp/shamela, not/mcp. - The client is on Streamable HTTP, not SSE.
- It asked for the list after the connection was established. Most clients have a refresh action for the tool list.
- The
Authorizationheader is either a real key or absent. - The library service behind the server may be briefly unreachable.
tools/listthen returns no tools, with HTTP 200, rather than listing tools that would fail. Wait a minute and reconnect. - Some clients cap the number of tools they will load across all servers. There are 14 here; turn off servers you do not need.