Skip to content

Inferensys/mcp-server-toolkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mcp-server-toolkit

If you are building a small MCP server, the hard part is not boilerplate. It is keeping the protocol edge obvious.

This toolkit implements the narrow slice that matters:

  • JSON-RPC request handling with explicit errors
  • MCP initialization and capability advertisement
  • typed tool registration with JSON Schema extraction
  • URI-template resources
  • typed prompt arguments and prompt rendering
  • stdio transport for local MCP clients and test harnesses

It does not try to be a batteries-included SDK. The point is to keep the server surface small enough to inspect in one sitting.

What Is In The Demo

src/mcp_server_toolkit/demo_server.py exposes one of each MCP primitive:

  • tool: incident_status
  • resource: ops://runbooks/{service}
  • prompt: incident_handoff

The checked-in session under demo/ exercises the full path:

  1. initialize
  2. notifications/initialized
  3. tools/list
  4. tools/call
  5. resources/list
  6. resources/read
  7. prompts/list
  8. prompts/get

Observed summary from demo/output/session-summary.json:

{
  "protocol_version": "2025-11-25",
  "tool_count": 1,
  "resource_count": 1,
  "prompt_count": 1,
  "called_tool": "INC-4821",
  "read_resource_uri": "ops://runbooks/billing-api",
  "prompt_name": "incident_handoff"
}

Observed tools/call result from demo/output/response-3.json:

{
  "content": [
    {
      "type": "text",
      "text": "{\n  \"incident_id\": \"INC-4821\",\n  \"status\": \"monitoring\",\n  \"service\": \"billing-api\",\n  \"severity\": \"sev2\",\n  \"owner\": \"payments-sre\",\n  \"next_update_utc\": \"2026-04-16T19:00:00Z\"\n}"
    }
  ],
  "structuredContent": {
    "incident_id": "INC-4821",
    "status": "monitoring",
    "service": "billing-api",
    "severity": "sev2",
    "owner": "payments-sre",
    "next_update_utc": "2026-04-16T19:00:00Z"
  },
  "isError": false
}

The prompt payload is also checked in. demo/output/response-7.json returns a message array ready to hand to an LLM rather than a flat string prompt.

Build A Server

from mcp_server_toolkit import (
    MCPServer,
    PromptMessage,
    PromptResult,
    ResourceContent,
    TextContent,
)

server = MCPServer(
    name="ops-toolkit",
    version="0.2.0",
    description="Operations MCP server",
)


@server.tool(description="Return operational incident status.")
def incident_status(incident_id: str, include_owner: bool = False) -> dict[str, object]:
    return {
        "incident_id": incident_id,
        "status": "monitoring",
        "include_owner": include_owner,
    }


@server.resource(
    uri_template="ops://runbooks/{service}",
    mime_type="text/markdown",
)
def runbook(service: str) -> ResourceContent:
    return ResourceContent(
        uri=f"ops://runbooks/{service}",
        text=f"# {service}\n\nCheck dashboards before escalating.",
        mime_type="text/markdown",
    )


@server.prompt(description="Draft an incident handoff.")
def incident_handoff(incident_id: str, audience: str) -> PromptResult:
    return PromptResult(
        description="Incident handoff prompt",
        messages=[
            PromptMessage(
                role="user",
                content=TextContent(
                    text=f"Draft a handoff for {incident_id} to {audience}."
                ),
            )
        ],
    )


server.run_stdio()

Run It

Install dependencies:

uv sync --extra dev

Replay the checked-in session and regenerate artifacts:

uv run python scripts/run_demo_session.py

Start the stdio server:

uv run python -m mcp_server_toolkit.demo_server

Send a manual request:

printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | \
  uv run python -m mcp_server_toolkit.demo_server

Operating Assumptions

  • tool input schemas should come from function signatures, not duplicate JSON blobs
  • server behavior should stay readable without stepping through framework internals
  • dict and list tool results should preserve structured payloads on the wire
  • resources should resolve from URI templates, not switch statements spread across handlers
  • prompts should return typed message arrays because that is the object MCP clients actually consume

Files Worth Reading

  • src/mcp_server_toolkit/server.py
  • src/mcp_server_toolkit/tool.py
  • src/mcp_server_toolkit/resource.py
  • src/mcp_server_toolkit/prompt.py
  • src/mcp_server_toolkit/demo_server.py
  • docs/protocol-notes.md

Verify

uv run pytest -q
uv run python -m compileall src scripts

About

Minimal MCP server toolkit with typed tools, resources, prompts, and stdio transport

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages