MCP Minimal Agent Demo Server

MCP Minimal Agent Demo Server

A demo MCP server exposing three simple tools (get_github_activity, get_site_content, contact_scott) to illustrate tool discovery and invocation within an LLM agent harness using the Model Context Protocol.

Category
访问服务器

README

MCP Agent Harness Demo

A minimal demonstration of an LLM agent harness using the Model Context Protocol (MCP).

This repository contains small Node.js/TypeScript and Python examples showing how an agent can:

  • discover tools from an MCP server;
  • expose those tools to an LLM;
  • let the model request tool calls;
  • execute those calls through MCP;
  • return tool results to the model;
  • continue the loop until the model produces a final response.

Important: This is demonstration code only. It is not production code and should not be treated as a secure, hardened, or complete agent framework.

The purpose of the repository is to make the mechanics of an MCP-based agent harness easy to inspect.

Architecture

At a high level:

User
  |
  v
LLM
  |
  | tool request
  v
Agent Harness
  |
  v
MCP Client
  |
  v
MCP Server
  |
  v
Tool Implementation
  |
  v
Tool Result
  |
  +------------------> LLM

The responsibilities are deliberately separated:

LLM      - decides what it thinks should happen
Harness  - manages the agent loop and conversation state
MCP      - standardises tool discovery and invocation
Tools    - perform the actual deterministic operations

MCP does not decide which tool should be called.

Tool selection remains a model decision unless the surrounding application explicitly constrains or overrides it.

Why This Repository Exists

A lot of agent-framework terminology can obscure what is actually happening.

The essential harness loop is little more than:

call model
    |
    v
did it request a tool?
    |
   / \
 no   yes
 |     |
answer execute tool
       |
       v
   return result
       |
       +----> call model again

This repository keeps that mechanism visible instead of hiding it behind a large agent framework.

Repository Layout

A typical layout is:

.
├── node/
│   ├── package.json
│   └── src/
│       ├── agent.ts
│       └── server.ts
│
└── python/
    ├── agent.py
    └── server.py

The exact directory names can be changed without affecting the architecture.

Example MCP Tools

The demo server exposes three deliberately simple hypothetical tools:

get_github_activity
get_site_content
contact_scott

These are only examples intended to demonstrate:

  • tool discovery;
  • tool schemas;
  • tool descriptions;
  • arguments;
  • execution;
  • result handling.

They are not intended to represent a real backend.

Node.js / TypeScript

Requirements

  • Node.js 20+
  • an OpenAI API key

Install dependencies:

npm install

Set the API key:

export OPENAI_API_KEY="sk-..."

Run the agent:

npm start

The MCP server is launched automatically by the agent through the stdio transport.

You should not need to run the server separately.

Example output:

MCP tools: [
  'get_github_activity',
  'get_site_content',
  'contact_scott'
]

MODEL REQUESTED TOOL: get_github_activity
ARGUMENTS: {}

MCP RESULT:
...

FINAL ANSWER
------------
Scott has recently been working on...

Python

Requirements

  • Python 3.10+
  • an OpenAI API key

Create a virtual environment:

python3 -m venv .venv
source .venv/bin/activate

Upgrade packaging tools:

python3 -m pip install --upgrade pip setuptools wheel

Install dependencies:

pip install "mcp>=2,<3" openai

Set the API key:

export OPENAI_API_KEY="sk-..."

Run:

python3 agent.py

The Python version runs as an interactive CLI chatbot:

MCP tools: ['get_github_activity', 'get_site_content', 'contact_scott']

Chat started.
Type /quit to exit.

You> hello

Assistant> Hello! How can I help?

You> What has Scott been working on?

  [tool] get_github_activity({})
  [result] ...

Assistant> Scott has recently been working on...

The Python client retains conversation history between turns and streams normal responses to the terminal.

Stdio Transport

These examples use MCP over stdio.

The agent launches the MCP server as a child process:

agent
  |
  +---- stdin/stdout ---- MCP server

This is convenient for local experimentation because there is:

  • no separate server daemon;
  • no HTTP endpoint;
  • no port configuration;
  • no additional authentication layer.

One important consequence is that an MCP stdio server must not write arbitrary debugging output to stdout.

stdout belongs to the MCP protocol.

Use stderr for diagnostics instead.

For example:

print("debug information", file=sys.stderr)

or in TypeScript:

console.error("debug information");

The Agent Harness

The essential harness logic is:

while True:
    response = await model(...)

    calls = find_tool_calls(response)

    if not calls:
        return

    for call in calls:
        result = await mcp.call_tool(
            call.name,
            call.arguments,
        )

        add_result_to_context(result)

A real harness may additionally implement:

permissions
timeouts
tool allowlists
human approval
rate limits
cost limits
logging
tracing
context pruning
retry policies
authentication
authorization
sandboxing
validation
auditing
error recovery

This demo intentionally does very little of that.

Tool Discovery

The harness does not need a hard-coded list of implementations.

Instead it asks the MCP server for its available tools.

Conceptually:

MCP server
    |
    | tools/list
    v
Agent harness

The harness then exposes the resulting:

name
description
input schema

to the model.

If the MCP server later adds another tool, the harness can discover it without adding another custom dispatch branch.

That is one of the main architectural benefits MCP provides.

Tool Selection Is Not Guaranteed

This point is important.

Suppose the server provides:

contact_scott

with a description saying it should be used when somebody wants to hire or contact Scott.

A user may say:

Can I hire Scott for consulting?

The desired model behaviour is:

contact_scott(...)

But an LLM may instead produce an ordinary conversational response.

MCP does not solve that problem.

The decision:

Does this natural-language request imply this tool?

is still probabilistic model inference.

Tool descriptions improve routing behaviour, but they do not create formal guarantees.

If an action must happen deterministically, that requirement should be enforced in ordinary application logic rather than relying solely on an LLM instruction.

Why This Matters

Once the model requests a tool, the rest of the system can be deterministic:

model requests tool
        |
        v
validate arguments
        |
        v
check permission
        |
        v
execute function
        |
        v
return result

But the initial semantic decision may still be probabilistic.

This distinction is particularly important for consequential actions such as:

sending money
deleting data
changing permissions
submitting legal information
making purchases
sending messages
altering customer records

A production system should place explicit deterministic controls around actions with meaningful consequences.

Streaming

The Python CLI uses streaming so text appears as it is generated.

Without streaming:

You> explain virtual memory

<wait>

Assistant> Virtual memory is...

With streaming:

You> explain virtual memory

Assistant> Virtual memory is...

Streaming primarily improves perceived latency.

Tool-using turns may still take longer because they can require multiple model requests:

model request
    |
    v
tool call
    |
    v
MCP execution
    |
    v
tool result
    |
    v
second model request

Demo Code — Not Production Code

This repository is intentionally minimal.

It does not provide the safeguards expected of a production agent system.

Among other things, production code would need to consider:

  • authentication;
  • authorization;
  • secret management;
  • hostile tool inputs;
  • prompt injection;
  • output validation;
  • tool-result validation;
  • schema enforcement;
  • resource limits;
  • network isolation;
  • subprocess security;
  • user confirmation for consequential operations;
  • audit logging;
  • retry behaviour;
  • failure recovery;
  • cost controls;
  • context growth;
  • model-version changes;
  • API-version changes;
  • dependency pinning;
  • observability;
  • testing and evaluation;
  • privacy and data-retention requirements.

Do not expose the example MCP server directly to untrusted users or use the example contact_scott pattern for real communications without adding appropriate validation, authentication, persistence, abuse protection, and error handling.

Again:

This repository is demo code intended for learning and experimentation, not production deployment.

MCP Is Not the Agent

It is useful to keep the layers separate:

MCP
    != LLM

MCP
    != agent

MCP
    != tool-selection logic

MCP
    != security policy

MCP is the protocol used to expose and invoke capabilities.

The harness manages the model/tool loop.

The model performs language inference.

The underlying tools perform the actual work.

A useful mental model is:

Agent System
=
Model
+
Harness
+
Tools
+
Context
+
Policy

MCP provides a standard interface between some of those components.

Why Not Just Call Functions Directly?

For three local functions in one application, you absolutely can.

For example:

TOOLS = {
    "foo": foo,
    "bar": bar,
}

may be simpler than MCP.

MCP becomes more interesting when capabilities need to be reusable across multiple clients:

                    MCP Server
                   /    |     \
                  /     |      \
                 /      |       \
            CLI agent  IDE    website

The tool provider becomes independent from any particular model host or application.

That is the main architectural reason to introduce MCP.

Suggested Experiments

Once the basic CLI works, useful experiments include:

run the same prompt repeatedly
change tool descriptions
change models
change system instructions
record selected tools
measure latency
measure token usage
add approval gates
add deliberately ambiguous prompts
add multiple MCP servers
introduce tool failures
introduce malformed results
limit maximum agent steps

One particularly useful test is to record:

prompt
selected tool
arguments
number of model calls
latency
final response

across repeated runs.

That makes it possible to examine how much variation comes from the model and how much behaviour can be controlled by the harness.

License

I just chose err whatever, do what you will. Nothing original here but if you bite your own ass - not my fault.

Final Note

The point of this code is not to provide another large agent framework.

It is to expose the machinery clearly enough that the core process can be understood:

Model proposes.
Harness controls.
MCP connects.
Tools execute.

Everything more sophisticated is built on top of that.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选