Practical guide · Intermediate
SEO Tools in Claude Code: Comparing Hosted and Local MCP
A coding agent cannot analyze the current search landscape if it cannot retrieve it. This guide connects Claude Code to live SERP data through the Model Context Protocol (MCP), then compares a hosted HTTP server with a local stdio server using the same query, location, language, device, and output contract.
The problem and the target result
Claude Code can inspect a repository, edit files, run commands, and reason over supplied context. That does not automatically give it access to a current search engine optimization (SEO) dataset. Without a search-data tool, the agent may know how to analyze rankings but cannot establish what ranks now for a particular market.
The usual workaround is manual: run a search in a browser or third-party platform, export the results, paste them into the session, and repeat whenever the query changes. This is slow and introduces several sources of error:
- the copied result may omit rank, result type, URL, or query parameters;
- the search may use an uncontrolled location, language, device, or logged-in state;
- the agent cannot repeat the retrieval while validating its own conclusion;
- two test runs may silently use different settings;
- large pasted responses consume context without a stable data contract.
The target result is narrower and more reliable: Claude Code should discover one MCP search tool, call it with explicit parameters, receive structured results, and save enough metadata for another person to repeat the call. You will configure two transports and compare them without assuming that either is universally better.
Hosted HTTP and local stdio
A hosted MCP server runs outside your machine and is reached over HTTPS. Claude Code connects to a remote endpoint, while the provider operates the server process and usually handles scaling and updates.
A local stdio transport starts a program on your machine and exchanges protocol messages through standard input and standard output. The program may retrieve SERP data from a remote search-data service, query a local index, or wrap another command-line tool. “Local MCP” describes where the MCP process runs; it does not prove that the underlying search data is local.
| Dimension | Hosted HTTP | Local stdio |
|---|---|---|
| Server operation | Handled by the remote operator | Handled on the developer machine |
| Connection | Remote HTTPS endpoint | Child process over stdin and stdout |
| Initial setup | Usually endpoint plus authentication | Runtime, package, command, and environment |
| Updates | May change remotely | Can be pinned to a known version |
| Debugging | Depends on remote logs and error detail | Local stderr and process inspection are available |
| Secret exposure | Credentials and requests reach a remote service | Local wrapper secrets remain local, but its upstream calls may not |
| Team consistency | One endpoint can simplify shared access | Requires reproducible local installation |
Transport is only one part of the system. A fair comparison must separate MCP connection behavior from the upstream search-data source. If the hosted server and the local server use different SERP providers, differences in rankings may come from provider collection methods rather than HTTP versus stdio.
The controlled SEO case
Assume a small editorial repository contains a draft about choosing an observability stack. The editor wants to understand the result types and competing pages for the query open source observability tools before revising the draft.
This is a reproducible demonstration query, not a claim about any company, customer, or ranking outcome. You may replace it with a query relevant to your site. Do not mix confidential product plans or unpublished customer terms into a third-party search API without authorization.
Freeze the request before testing
Create a test specification and use it unchanged for both transports:
{
"query": "open source observability tools",
"country": "us",
"language": "en",
"device": "desktop",
"limit": 10,
"safe_search": true
}
The exact field names will depend on your MCP server. Map them once, then record the final arguments actually sent. If a server supports a location identifier rather than a country code, choose one location and use its equivalent in both calls.
Define the minimum result contract
Ask each server to return, where the provider exposes them:
- the normalized query;
- country or location, language, and device;
- retrieval time or provider timestamp;
- organic rank, title, URL, and visible description;
- result type, such as organic result, video, news, or featured block;
- provider warnings, truncation flags, and request identifiers;
- the tool name and tool-schema version if available.
Do not force the agent to infer missing metadata. A list of URLs without locale and retrieval time is not adequate evidence for a current ranking analysis.
Prerequisites and safety
You need Claude Code, a terminal, and access to an MCP server that exposes a legitimate search or SERP retrieval tool. For a local package, you also need its supported runtime. Examples below use placeholders because server names, tool schemas, authentication methods, and Claude Code command options can vary by version and provider.
Collect these values
HOSTED_MCP_URL: the documented HTTPS endpoint;HOSTED_MCP_TOKEN: a scoped token if the endpoint requires one;LOCAL_MCP_COMMAND: the documented executable or package runner;SERP_API_KEY: an upstream credential if the local server needs one;- the exact search tool name and input schema for both servers.
An API key must not be committed to the repository, pasted into an article, placed in shell history unnecessarily, or written into a project-scoped MCP file that teammates will commit. Prefer environment-variable references, an operating-system secret store, or the authentication mechanism documented by the server.
Inspect Claude Code’s current command syntax
Start with the installed client rather than copying a version-specific command blindly:
claude --version
claude mcp --help
claude mcp add --help
claude mcp list
Use the forms shown by your installed version. The examples in the next sections illustrate the configuration intent and use placeholder names; they do not assert that every release accepts identical flags.
Connect a hosted HTTP MCP server
A Streamable HTTP transport lets an MCP client communicate with a remote server through an HTTP endpoint. Use the server operator’s documented URL and authentication header. Do not guess endpoint paths.
1. Put the token in the environment
export HOSTED_MCP_TOKEN='replace-with-your-scoped-token'
This export lasts for the current shell session. For regular use, load the value through your approved secret-management workflow rather than storing the literal token in a repository file.
2. Add the server
If your installed Claude Code version supports an HTTP type and header expansion, the command may follow this pattern:
claude mcp add \
--transport http \
--header "Authorization: Bearer ${HOSTED_MCP_TOKEN}" \
seo-hosted \
"https://YOUR-MCP-HOST.example/mcp"
Replace the URL and flags with the values from claude mcp add --help and the server documentation. If the client stores configuration in JSON, use the equivalent remote-server entry while keeping the secret out of committed text.
3. Confirm registration and connection
claude mcp list
claude mcp get seo-hosted
Check that the displayed transport is HTTP, the hostname is correct, and the secret is redacted. Then open Claude Code and inspect the MCP server status using the client’s MCP interface. The connection is not verified merely because a configuration entry exists.
4. Inspect tools before asking for analysis
Confirm that the server exposes a search tool and read its schema. A plausible name such as search_serp is not evidence that this is the real tool name. Note required fields, allowed country and device values, maximum result count, and whether retrieval time is included.
5. Run a narrow smoke test
In Claude Code, use a prompt that requires a tool call but does not yet ask for strategic conclusions:
Use only the MCP server named seo-hosted.
Find its tool for retrieving a current search results page. Show me:
1. the exact tool name,
2. the input arguments you will send,
3. the retrieval result for this fixed request:
query: open source observability tools
country: US
language: English
device: desktop
limit: 10
Do not estimate rankings from memory. If a parameter is unsupported,
stop and identify it. Preserve the returned order and include the
retrieval timestamp or explicitly state that the provider omitted it.
Save the tool-call arguments and raw structured response outside the conversational summary. Do not edit rankings by hand.
Connect a local stdio MCP server
The local variant should expose equivalent search functionality. Ideally, both servers should use the same upstream data provider and compatible parameters. Otherwise, label the experiment as an end-to-end implementation comparison rather than a pure transport benchmark.
1. Pin and inspect the package
Use the server’s official installation instructions. Avoid an unpinned “latest” dependency in a repeatable benchmark. Before running a third-party package, inspect its source, package ownership, requested permissions, and release information.
A generic package-runner pattern looks like this:
npx --yes @YOUR-SCOPE/seo-mcp-server@PINNED_VERSION --help
For Python-based servers, the documented command might instead use an isolated runner or virtual environment. The key requirement is a specific reviewed package version, not a particular ecosystem.
2. Provide the upstream credential
export SERP_API_KEY='replace-with-your-scoped-key'
If the server supports a mock, cached, or local index mode, decide whether that mode satisfies the goal. Cached results can test MCP integration, but they do not prove access to a current SERP.
3. Add the stdio process
Depending on the installed CLI syntax, a stdio registration may resemble:
claude mcp add \
--transport stdio \
--env SERP_API_KEY="${SERP_API_KEY}" \
seo-local \
-- npx --yes @YOUR-SCOPE/seo-mcp-server@PINNED_VERSION
Some versions separate Claude Code options from the child command differently. Confirm the separator, environment syntax, and configuration scope with the local help output.
4. Keep protocol output clean
A stdio MCP process must reserve stdout for protocol messages. Debug banners and ordinary logs should go to stderr. A package that prints installation notices or colored logs to stdout can corrupt communication even when its underlying search request succeeds.
5. Confirm the local process and tools
claude mcp list
claude mcp get seo-local
Start Claude Code from the same environment that contains the required runtime and credential. Inspect server status and compare the local tool schema with the hosted schema. Record any mismatch before running the shared test.
6. Run the equivalent smoke test
Use only the MCP server named seo-local.
Find its tool for retrieving a current search results page. Show me:
1. the exact tool name,
2. the input arguments you will send,
3. the retrieval result for this fixed request:
query: open source observability tools
country: US
language: English
device: desktop
limit: 10
Do not estimate rankings from memory. If a parameter is unsupported,
stop and identify it. Preserve the returned order and include the
retrieval timestamp or explicitly state that the provider omitted it.
Run a fair hosted-versus-local comparison
The central mistake in MCP comparisons is asking each server a broad question and comparing the prose answers. That measures agent wording, prompt variation, and possibly different tool choices. Compare the tool calls and raw records first; analyze them second.
Test protocol
- Use the same Claude Code version and model configuration.
- Start both runs from fresh sessions to avoid one result contaminating the other.
- Use the fixed query, locale, language, device, result limit, and safety setting.
- Run the calls as close together as practical, recording the actual timestamps.
- Require each session to use only its named MCP server.
- Capture the exact tool name, arguments, structured response, errors, and warnings.
- Do not retry silently. Record every attempt and the reason for a retry.
- Normalize only presentation differences; preserve original records separately.
Use one output schema
Ask Claude Code to write or display a normalized record like the following. Keep missing values as null; do not fill them with guesses:
{
"transport": "hosted-http-or-local-stdio",
"server_name": "configured-server-name",
"tool_name": "actual-tool-name",
"started_at": "observed-ISO-8601-time",
"completed_at": "observed-ISO-8601-time",
"request": {
"query": "open source observability tools",
"country": "us",
"language": "en",
"device": "desktop",
"limit": 10
},
"provider_metadata": {
"retrieved_at": null,
"request_id": null,
"cache_status": null
},
"results": [
{
"rank": 1,
"type": "organic",
"title": "value-returned-by-provider",
"url": "value-returned-by-provider",
"displayed_url": null,
"description": null
}
],
"warnings": [],
"error": null
}
Record observations, not expected winners
Use an empty worksheet before the test and populate it only from observed behavior:
| Measure | Hosted HTTP | Local stdio | How to verify |
|---|---|---|---|
| Connected successfully | Not tested | Not tested | Client status and successful tool discovery |
| Tool name | Record actual value | Record actual value | Tool inventory |
| Parameters supported | Record actual fields | Record actual fields | Published tool schema |
| Result count | Record actual count | Record actual count | Count structured records |
| Metadata completeness | Record missing fields | Record missing fields | Inspect raw response |
| Elapsed time | Measure locally | Measure locally | Completion minus start time |
| Retries | Record attempts | Record attempts | Session and server logs |
| Top-10 URL overlap | Calculate after both successful calls | Compare normalized URLs | |
Calculate overlap without pretending it proves accuracy
Normalize URLs conservatively: lowercase the hostname, remove fragments, and remove only tracking parameters that you can identify safely. Do not collapse distinct paths or canonicalize URLs based on assumptions.
For two sets of returned URLs, calculate:
overlap_count = number of normalized URLs present in both result sets
union_count = number of unique normalized URLs across both sets
jaccard = overlap_count / union_count
A high overlap shows agreement between the observed datasets. It does not prove that either dataset exactly matches what an anonymous person would see in a browser. A low overlap may indicate timing, locale, personalization, caching, parameter mapping, provider differences, or parsing behavior.
Measure rank movement separately
For URLs present in both responses, record their rank difference:
rank_delta = local_stdio_rank - hosted_http_rank
Keep the sign convention in the report. Do not average rank deltas while ignoring URLs that appear in only one response; report shared URLs and exclusive URLs separately.
Verify that the agent used live tool data
A fluent answer is not verification. Require a traceable path from connection to tool call to structured output.
Connection checks
- Both configured names appear in the MCP server list.
- The hosted entry points to the intended HTTPS hostname.
- The local entry launches the intended pinned command.
- Secrets are not printed in status output or saved artifacts.
- Each server reports a usable state in the Claude Code session.
Tool checks
- The agent names the actual discovered tool rather than inventing one.
- The arguments match the fixed test specification.
- Unsupported parameters are reported instead of silently dropped.
- The result order is preserved.
- The raw response contains the URLs summarized by the agent.
Freshness checks
- Prefer a provider retrieval timestamp over the agent’s session time.
- Record cache status and cache age when exposed.
- If no freshness metadata exists, label freshness as unverified.
- Do not describe a result as “live” merely because the network call succeeded.
Ask for a provenance report
For the SERP data you just returned, provide a provenance report.
Include:
- MCP server name;
- exact tool name;
- exact tool arguments;
- provider retrieval timestamp, if returned;
- cache status, if returned;
- fields omitted by the provider;
- any transformation you performed;
- any claim in your summary that was not directly supported by tool output.
Do not call another tool and do not reconstruct missing metadata.
Optional browser spot-check
A manual search can identify obvious anomalies, but it is not a ground-truth replacement unless the environment is controlled. Search engines may vary results by precise location, time, data center, consent state, personalization, and page layout. Record the browser’s settings and timestamp, and call the exercise a spot-check rather than a definitive accuracy test.
Failure cases and diagnosis
The hosted server is unauthorized
Symptoms: an HTTP 401 or 403 response, failed tool discovery, or repeated authentication prompts.
Checks: verify that the token is present in the environment used to start Claude Code, confirm the expected header name and token prefix, inspect token scope and expiry, and ensure the endpoint belongs to the intended environment. Never print the full token while debugging.
The endpoint connects but exposes no search tool
Symptoms: server status is healthy, but the required SERP tool is absent.
Checks: confirm that you used the correct MCP endpoint, account plan, workspace, and server version. Review the discovered tool list. A healthy MCP server can still be the wrong server.
The local server exits immediately
Symptoms: disconnected status, process-not-found errors, or failure during initialization.
Checks: run the documented command with --help, confirm the runtime is available in Claude Code’s environment, check the pinned package version, and inspect stderr. A command that works in an interactive shell may fail when PATH or environment initialization differs.
Protocol parsing fails on stdio
Symptoms: malformed-message errors, unexpected characters, or initialization timeouts.
Checks: look for banners, debug logs, progress bars, or package-manager notices written to stdout. Configure logs for stderr, disable decorative output, and avoid wrappers that inject text into the protocol stream.
The tool rejects locale or device values
Symptoms: validation errors or silently changed parameters.
Checks: inspect the tool’s input schema. One server may accept us, another United States, and another a numeric location ID. Document the mapping. If equivalent targeting cannot be established, do not call the output comparison controlled.
The response is empty
Symptoms: a successful tool call with no results.
Checks: inspect warnings, quota status, safety settings, query encoding, locale support, and provider response fields. Do not let the agent replace an empty response with remembered or inferred rankings.
The response is too large for useful analysis
Symptoms: context pressure, truncated tool output, or missing lower-ranked records.
Checks: request only the needed result count and fields. Separate retrieval from page-content extraction. Ten result records are usually more useful for an initial test than complete HTML from ten pages.
Hosted and local outputs differ
Symptoms: different URLs, rank order, result types, or metadata.
Checks: compare request timestamps, provider identity, location mapping, language, device, cache status, safe-search setting, normalization rules, pagination, and parser version. Do not attribute the difference to transport until these variables are controlled.
The agent answers without calling either tool
Symptoms: no tool trace, generic competitors, missing timestamps, or claims such as “current rankings” without records.
Checks: constrain the prompt to one named server, require exact arguments and provenance, and state that the task must stop if the tool is unavailable. Treat an untraced response as a failed run.
Rate limits or costs distort the test
Symptoms: throttling, long backoff, partial results, or unexpected consumption.
Checks: review quotas before testing, limit results, avoid uncontrolled retries, and record provider error codes. A cheaper transport does not imply cheaper search data; the upstream request may dominate cost.
Limitations and selection guidance
What this comparison can establish
- whether each MCP connection works in your Claude Code environment;
- whether the required query parameters are supported;
- whether output is sufficiently structured and traceable;
- the observed latency, errors, metadata, and result agreement for the test;
- the operational work required by each configuration.
What one query cannot establish
- general accuracy across markets, languages, devices, and result types;
- long-term reliability or provider uptime;
- typical performance under concurrency;
- complete privacy, security, or compliance characteristics;
- that HTTP or stdio caused differences in search results;
- that the provider’s dataset matches every user’s visible search page.
Choose hosted HTTP when
- the team needs a centrally operated endpoint;
- developers should not install and maintain a local runtime;
- remote authentication and access controls fit the organization’s policy;
- the provider offers the observability, retention policy, and data handling you require;
- consistent rollout matters more than local process control.
Choose local stdio when
- you need to inspect or modify the MCP wrapper;
- you want to pin the server implementation to a reviewed version;
- local stderr and process-level debugging are valuable;
- the team can reproduce the runtime and package installation;
- credentials must be injected through a local secret workflow.
Neither choice eliminates the need to evaluate the upstream SERP source. A local wrapper around a remote API still sends queries to that API. A hosted server may also be a thin wrapper around the same provider. Document both layers: the MCP transport and the search-data origin.
A repeatable operating workflow
Once the comparison passes, turn it into a small, controlled research procedure rather than an open-ended “do SEO” prompt.
Phase 1: Retrieve
Use seo-hosted to retrieve exactly 10 results for the fixed request.
Return structured records and provenance only. Do not recommend changes yet.
Phase 2: Validate
Check the returned records for missing rank, URL, result type, locale,
device, retrieval time, cache status, warnings, and truncation.
Mark each missing field as unknown. Do not infer it.
Phase 3: Analyze
Using only the validated records, identify:
- recurring page formats;
- dominant search intent;
- result features visible in the dataset;
- title patterns;
- domains appearing more than once.
Separate direct observations from hypotheses. Do not claim traffic,
search volume, authority, or content quality unless the tool returned
evidence for those claims.
Phase 4: Apply to the repository
Compare the validated SERP observations with the current draft.
Propose changes that are supported by the evidence.
Do not rewrite files until you show:
1. the evidence,
2. the proposed change,
3. the expected editorial effect.
Phase 5: Preserve an audit record
Store the query specification, timestamps, server names, tool names, normalized records, raw-response location, warnings, and analysis prompt. Exclude credentials and sensitive headers. If the repository should not contain research data, store the record in the approved external location and reference only its identifier.
Final checklist
- The hosted server uses the documented HTTPS endpoint.
- The local server command is reviewed and version-pinned.
- Secrets are scoped and absent from committed files.
- Both servers expose an appropriate search tool.
- The fixed request uses the same query, locale, language, device, and limit.
- Both runs record actual timestamps and every retry.
- Raw responses are preserved before normalization.
- Missing metadata remains unknown rather than inferred.
- URL overlap and rank differences are calculated from observed records.
- Provider differences are not misattributed to MCP transport.
- The final SEO analysis distinguishes evidence from hypotheses.
The practical success criterion is simple: the coding agent no longer needs a person to paste a search result into every session, yet every ranking claim remains tied to an explicit tool call and a reproducible request. Hosted HTTP reduces local operational work; local stdio offers greater control over the wrapper and runtime. Your recorded test—not an assumed benchmark—should decide which trade-off fits the project.