-
Notifications
You must be signed in to change notification settings - Fork 1
Add 6 Agent Skills for Markdown-LD knowledge bank #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| --- | ||
| name: knowledge-graph-mcp | ||
| description: Build an MCP (Model Context Protocol) server that exposes a Markdown-LD knowledge graph to AI agents. Provides tool definitions for SPARQL queries, natural language questions, entity listing, and article discovery. Use when creating an MCP server to make a knowledge bank queryable by LLMs and agent frameworks. | ||
| --- | ||
|
|
||
| # Knowledge Graph MCP Server | ||
|
|
||
| Build an [MCP server](https://modelcontextprotocol.io/) that wraps a Markdown-LD knowledge bank, letting any AI agent query the knowledge graph through structured tool calls. | ||
|
|
||
| ## Why MCP? | ||
|
|
||
| The knowledge bank already has HTTP endpoints (`/api/sparql`, `/api/ask`). An MCP server adds: | ||
|
|
||
| - **Agent discoverability** — Agents automatically discover available tools | ||
| - **Structured input/output** — Zod/Pydantic schemas for parameters and results | ||
| - **Tool annotations** — Read-only hints, descriptions that help agents choose tools | ||
| - **Local or remote** — Works via stdio (local) or streamable HTTP (remote) | ||
|
|
||
| ## Architecture | ||
|
|
||
| ``` | ||
| Agent (Claude, Copilot, etc.) | ||
| ↕ MCP Protocol (stdio or HTTP) | ||
| MCP Server | ||
| ↕ RDFLib (local) or HTTP (remote) | ||
| Knowledge Graph (Turtle files) | ||
| ``` | ||
|
|
||
| Two deployment modes: | ||
|
|
||
| 1. **Local mode** — MCP server loads `.ttl` files directly into RDFLib | ||
| 2. **Remote mode** — MCP server proxies to the deployed Azure Functions API | ||
|
|
||
| ## Tool Definitions | ||
|
|
||
| ### 1. `query_sparql` | ||
|
|
||
| Execute a SPARQL query against the knowledge graph. | ||
|
|
||
| ```python | ||
| @mcp.tool( | ||
| annotations={ | ||
| "readOnlyHint": True, | ||
| "openWorldHint": False, | ||
| } | ||
| ) | ||
| def query_sparql(query: str) -> str: | ||
| """Execute a SPARQL 1.1 SELECT or ASK query against the knowledge graph. | ||
|
|
||
| The graph uses schema.org vocabulary. Available prefixes: | ||
| - schema: <https://schema.org/> | ||
| - kb: <https://example.com/vocab/kb#> | ||
| - prov: <http://www.w3.org/ns/prov#> | ||
|
|
||
| Only SELECT and ASK queries are allowed. Include a LIMIT clause. | ||
|
|
||
| Args: | ||
| query: A valid SPARQL 1.1 query string with PREFIX declarations. | ||
|
|
||
| Returns: | ||
| JSON string with SPARQL Results JSON format. | ||
| """ | ||
| ``` | ||
|
|
||
| ### 2. `ask_question` | ||
|
|
||
| Natural language query — the server translates to SPARQL. | ||
|
|
||
| ```python | ||
| @mcp.tool( | ||
| annotations={ | ||
| "readOnlyHint": True, | ||
| "openWorldHint": False, | ||
| } | ||
| ) | ||
| def ask_question(question: str) -> str: | ||
| """Ask a natural language question about the knowledge graph. | ||
|
|
||
| The question is translated to SPARQL and executed. The response | ||
| includes both the generated SPARQL and the results. | ||
|
|
||
| Example questions: | ||
| - "What entities are in the knowledge graph?" | ||
| - "Which articles mention SPARQL?" | ||
| - "Find all organizations" | ||
|
|
||
| Args: | ||
| question: A natural language question about the knowledge. | ||
|
|
||
| Returns: | ||
| JSON with 'question', 'sparql', and 'results' fields. | ||
| """ | ||
| ``` | ||
|
Comment on lines
+65
to
+93
|
||
|
|
||
| ### 3. `list_entities` | ||
|
|
||
| Browse entities with optional type filter. | ||
|
|
||
| ```python | ||
| @mcp.tool( | ||
| annotations={ | ||
| "readOnlyHint": True, | ||
| "openWorldHint": False, | ||
| } | ||
| ) | ||
| def list_entities(entity_type: str = "schema:Thing", limit: int = 50) -> str: | ||
| """List entities in the knowledge graph, optionally filtered by type. | ||
|
|
||
| Available types: schema:Person, schema:Organization, | ||
| schema:SoftwareApplication, schema:CreativeWork, schema:Thing | ||
|
|
||
| Args: | ||
| entity_type: Schema.org type to filter by (default: all entities). | ||
| limit: Maximum number of results (default: 50). | ||
|
|
||
| Returns: | ||
| JSON array of entities with id, name, and type. | ||
| """ | ||
| ``` | ||
|
|
||
| ### 4. `list_articles` | ||
|
|
||
| Discover articles in the knowledge bank. | ||
|
|
||
| ```python | ||
| @mcp.tool( | ||
| annotations={ | ||
| "readOnlyHint": True, | ||
| "openWorldHint": False, | ||
| } | ||
| ) | ||
| def list_articles(limit: int = 50) -> str: | ||
| """List articles in the knowledge bank. | ||
|
|
||
| Args: | ||
| limit: Maximum number of results (default: 50). | ||
|
|
||
| Returns: | ||
| JSON array of articles with id, title, datePublished, and keywords. | ||
| """ | ||
| ``` | ||
|
|
||
| ### 5. `get_entity_details` | ||
|
|
||
| Deep-dive into a specific entity's relationships. | ||
|
|
||
| ```python | ||
| @mcp.tool( | ||
| annotations={ | ||
| "readOnlyHint": True, | ||
| "openWorldHint": False, | ||
| } | ||
| ) | ||
| def get_entity_details(entity_name: str) -> str: | ||
| """Get detailed information about a specific entity. | ||
|
|
||
| Returns the entity's type, sameAs links, articles that mention it, | ||
| and related entities. | ||
|
|
||
| Args: | ||
| entity_name: The name of the entity to look up (case-insensitive). | ||
|
|
||
| Returns: | ||
| JSON with entity details and relationships. | ||
| """ | ||
| ``` | ||
|
|
||
| ## Implementation (Python / FastMCP) | ||
|
|
||
| See [scripts/server.py](scripts/server.py) for a complete reference implementation. | ||
|
|
||
| ### Quick Start | ||
|
|
||
| ```bash | ||
| # Install dependencies | ||
| pip install mcp rdflib | ||
|
|
||
| # Run locally (stdio transport) | ||
| python scripts/server.py --graph-dir ./graph/articles | ||
|
|
||
| # Run as HTTP server | ||
| python scripts/server.py --transport http --port 8080 | ||
| ``` | ||
|
|
||
| ### Connecting to an Agent | ||
|
|
||
| **Claude Code / Copilot:** | ||
| ```json | ||
| { | ||
| "mcpServers": { | ||
| "knowledge-graph": { | ||
| "command": "python", | ||
| "args": ["skills/knowledge-graph-mcp/scripts/server.py", "--graph-dir", "./graph/articles"] | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Safety | ||
|
|
||
| All tools are read-only: | ||
| - SPARQL queries are validated: `INSERT`, `DELETE`, `LOAD`, `CLEAR`, `DROP`, `CREATE` are blocked | ||
| - A `LIMIT` clause is injected if missing (default 100) | ||
| - No authentication required for read access | ||
|
|
||
| ## Error Handling | ||
|
|
||
| Return clear, actionable errors: | ||
|
|
||
| ```python | ||
| if not is_valid: | ||
| return json.dumps({ | ||
| "error": f"Invalid SPARQL syntax: {error_msg}", | ||
| "hint": "Check PREFIX declarations and property names. " | ||
| "Available properties: schema:name, schema:mentions, schema:about, ..." | ||
| }) | ||
| ``` | ||
|
|
||
| ## Reference | ||
|
|
||
| - [references/api-reference.md](references/api-reference.md) — Full API endpoint documentation | ||
| - [scripts/server.py](scripts/server.py) — Reference MCP server implementation | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # API Reference | ||
|
|
||
| The Markdown-LD knowledge bank exposes two HTTP endpoints via Azure Functions. | ||
|
|
||
| ## `GET/POST /api/sparql` | ||
|
|
||
| Execute SPARQL 1.1 queries against the knowledge graph. | ||
|
|
||
| ### GET | ||
|
|
||
| ``` | ||
| GET /api/sparql?query={url-encoded-sparql} | ||
| ``` | ||
|
|
||
| ### POST (preferred for complex queries) | ||
|
|
||
| ``` | ||
| POST /api/sparql | ||
| Content-Type: application/sparql-query | ||
|
|
||
| PREFIX schema: <https://schema.org/> | ||
| SELECT ?name WHERE { ?e schema:name ?name } | ||
| ``` | ||
|
|
||
| ### POST (form-encoded) | ||
|
|
||
| ``` | ||
| POST /api/sparql | ||
| Content-Type: application/x-www-form-urlencoded | ||
|
|
||
| query=PREFIX+schema... | ||
| ``` | ||
|
|
||
| ### Response | ||
|
|
||
| ``` | ||
| Content-Type: application/sparql-results+json | ||
|
|
||
| { | ||
| "head": { "vars": ["name"] }, | ||
| "results": { | ||
| "bindings": [ | ||
| { "name": { "type": "literal", "value": "Neo4j" } } | ||
| ] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Errors | ||
|
|
||
| - `400` — Missing query parameter or SPARQL syntax error | ||
| - `403` — Mutating query detected (INSERT, DELETE, etc.) | ||
|
|
||
| ### Headers | ||
|
|
||
| ``` | ||
| Access-Control-Allow-Origin: * | ||
| Cache-Control: public, max-age=300 | ||
| ``` | ||
|
|
||
| ## `GET/POST /api/ask` | ||
|
|
||
| Translate natural language to SPARQL and execute. | ||
|
|
||
| ### GET | ||
|
|
||
| ``` | ||
| GET /api/ask?question={url-encoded-question} | ||
| ``` | ||
|
|
||
| ### POST (preferred) | ||
|
|
||
| ``` | ||
| POST /api/ask | ||
| Content-Type: application/json | ||
|
|
||
| {"question": "What entities are in the knowledge graph?"} | ||
| ``` | ||
|
|
||
| ### Response | ||
|
|
||
| ```json | ||
| { | ||
| "question": "What entities are in the knowledge graph?", | ||
| "sparql": "PREFIX schema: <https://schema.org/>\nSELECT DISTINCT ?entity ?name ?type WHERE {\n ?entity a ?type ;\n schema:name ?name .\n FILTER(?type != schema:Article)\n}\nLIMIT 100", | ||
| "results": { | ||
| "head": { "vars": ["entity", "name", "type"] }, | ||
| "results": { "bindings": [...] } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Errors | ||
|
|
||
| - `400` — Missing question parameter or SPARQL execution error | ||
| - `502` — LLM rate limit or API error | ||
|
|
||
| ### Requirements | ||
|
|
||
| The `/api/ask` endpoint requires `GITHUB_TOKEN` as an environment variable for LLM access (GitHub Models). The `/api/sparql` endpoint works without any configuration. | ||
|
|
||
| ## Available Schema | ||
|
|
||
| ### Classes | ||
|
|
||
| | Class | Description | | ||
| |-------|-------------| | ||
| | `schema:Article` | A Markdown article | | ||
| | `schema:Person` | A person | | ||
| | `schema:Organization` | A company, foundation, or team | | ||
| | `schema:SoftwareApplication` | Software tools and libraries | | ||
| | `schema:CreativeWork` | Books, papers, specs | | ||
| | `schema:Thing` | Base type for any entity | | ||
|
|
||
| ### Properties | ||
|
|
||
| | Property | Domain → Range | | ||
| |----------|---------------| | ||
| | `schema:name` | Any → string | | ||
| | `schema:mentions` | Article → Thing | | ||
| | `schema:about` | Article → Thing | | ||
| | `schema:author` | Article → Person | | ||
| | `schema:creator` | Thing → Person/Org | | ||
| | `schema:datePublished` | Article → date | | ||
| | `schema:dateModified` | Article → date | | ||
| | `schema:sameAs` | Thing → URI | | ||
| | `schema:keywords` | Article → string | | ||
| | `schema:description` | Article → string | | ||
| | `kb:relatedTo` | Thing → Thing | | ||
| | `kb:confidence` | Assertion → decimal | | ||
| | `prov:wasDerivedFrom` | Assertion → URI | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section describes a “Remote mode” that proxies to a deployed API, but the reference implementation in
scripts/server.pydoes not currently implement an--api-urloption or any HTTP proxy behavior. Please either implement the remote mode or remove/clarify these deployment-mode claims so the skill stays accurate.